├── .gitignore ├── .semver ├── Gemfile ├── MassTransit.snk ├── README.md ├── build_support ├── BuildUtils.rb ├── util.rb └── versioning.rb ├── rakefile.rb ├── setup_sql_server.sql └── src ├── .nuget ├── NuGet.Config ├── NuGet.targets └── packages.config ├── MassTransit.Quartz.sln ├── MassTransit.Quartz.sln.DotSettings ├── MassTransit.QuartzIntegration.Tests ├── App.config ├── ContextSetup.cs ├── JobDetail_Specs.cs ├── MassTransit.QuartzIntegration.Tests.csproj ├── PastEvent_Specs.cs ├── Service_Specs.cs ├── Syntax_Specs.cs ├── Utils.cs ├── job_scheduling_data_2_0.xsd ├── log4net.config └── packages.config ├── MassTransit.QuartzIntegration ├── CancelScheduledMessageConsumer.cs ├── CancelScheduledTimeoutConsumer.cs ├── MassTransit.QuartzIntegration.csproj ├── MassTransitJobFactory.cs ├── ScheduleMessageConsumer.cs ├── ScheduleMessageJobBuilder.cs ├── ScheduleMessageJobBuilderImpl.cs ├── ScheduleTimeoutConsumer.cs ├── ScheduledMessageContext.cs ├── ScheduledMessageJob.cs ├── ScheduledTimeoutJob.cs ├── job_scheduling_data_2_0.xsd └── packages.config ├── MassTransit.QuartzService ├── Configuration │ ├── ConfigurationProviderExtensions.cs │ ├── ConnectionStringProvider.cs │ ├── FileConfigurationProvider.cs │ ├── IConfigurationProvider.cs │ ├── IConnectionProvider.cs │ ├── IConnectionStringProvider.cs │ └── SqlConnectionProvider.cs ├── MassTransit.QuartzService.csproj ├── Program.cs ├── ScheduleMessageService.cs ├── app.config ├── job_scheduling_data_2_0.xsd ├── log4net.config └── packages.config ├── MassTransit.Scheduling ├── CancelScheduledMessage.cs ├── MassTransit.Scheduling.csproj ├── ScheduleMessage.cs ├── ScheduleMessageExtensions.cs ├── ScheduledMessage.cs └── packages.config └── packages └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | build_artifacts/* 2 | build_output/* 3 | 4 | **/*.suo 5 | **/**/*.suo 6 | **/*.user 7 | **/**/*.user 8 | 9 | bin 10 | obj 11 | _ReSharper* 12 | *.dotCover 13 | 14 | *.csproj.user 15 | *.resharper.user 16 | *.ReSharper.user 17 | *.cache 18 | *~ 19 | *.swp 20 | *.bak 21 | *.orig 22 | *.user 23 | 24 | NuGet.exe 25 | src/packages/**/* 26 | docs/build/**/* 27 | 28 | .DS_Store 29 | 30 | TestResult.xml 31 | submit.xml 32 | src/tests/* 33 | tests/* 34 | SolutionVersion.cs 35 | -------------------------------------------------------------------------------- /.semver: -------------------------------------------------------------------------------- 1 | --- 2 | :major: 1 3 | :minor: 2 4 | :patch: 12 5 | :special: '' 6 | :metadata: '' 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'albacore', '~> 0.3.6' 4 | gem 'rake' 5 | gem 'semver2' -------------------------------------------------------------------------------- /MassTransit.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MassTransit/MassTransit-Quartz/49807746daa64b7573b0a1346f81f2f84e557918/MassTransit.snk -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MassTransit-Quartz 2 | ================== 3 | 4 | Quartz support for MassTransit 5 | 6 | Possible API 7 | ============== 8 | 9 | Create a service that will allow messages to be scheduled. 10 | 11 | For example, 12 | 13 | var handle = bus.SchedulePublish(30.Seconds().FromNow, new MyMessage(someId, someValue)); 14 | 15 | The default implementation can be in memory, but we can also serialize the message to Json and store it for later resubmission via the bus. 16 | 17 | Should probably have a SchedulePublish() and a ScheduleSend(endpoint, ...) so that direct sends as well as publishes can be supported, including forging the sender address to be that of the original requestor (instead of the scheduled message service). 18 | 19 | Guid tokenId = handle.TokenId; 20 | 21 | bus.CancelScheduledMessage(tokenId); 22 | or handle.Cancel(); if the handle is still around (just a closure around the bus and method). -------------------------------------------------------------------------------- /build_support/BuildUtils.rb: -------------------------------------------------------------------------------- 1 | require 'erb' 2 | 3 | class NUnitRunner 4 | include FileTest 5 | 6 | def initialize(command, working_directory, framework, flags) 7 | @command = command 8 | @working_directory = working_directory 9 | @framework = framework || 'v4.0' 10 | @flags = flags 11 | 12 | # prepare the command 13 | @cmd = "#{command} /framework=#{@framework}" 14 | @cmd += ' ' + @flags.join(' ') unless @flags.nil? 15 | end 16 | 17 | def run(assemblies) 18 | assemblies.each do |assem| 19 | file = File.expand_path("#{@working_directory}/#{assem}") 20 | Kernel::system("#{@cmd} \"#{file}\"") 21 | end 22 | end 23 | end 24 | 25 | class MSBuildRunner 26 | def self.compile(attributes) 27 | build_config = attributes.fetch(:build_config) 28 | solutionFile = attributes[:solutionfile] 29 | 30 | attributes[:projFile] = solutionFile 31 | attributes[:properties] ||= [] 32 | attributes[:properties] << "Configuration=#{build_config}" 33 | attributes[:extraSwitches] = ["maxcpucount:2", "v:m", "t:rebuild"] 34 | 35 | self.runProjFile(attributes); 36 | end 37 | 38 | def self.runProjFile(attributes) 39 | version = attributes.fetch(:clrversion, 'v4.0.30319') 40 | build_config = attributes.fetch(:build_config, 'debug') 41 | projFile = attributes[:projFile] 42 | 43 | frameworkDir = File.join(ENV['windir'].dup, 'Microsoft.NET', 'Framework', version) 44 | msbuildFile = File.join(frameworkDir, 'msbuild.exe') 45 | 46 | properties = attributes.fetch(:properties, []) 47 | 48 | switchesValue = "" 49 | 50 | properties.each do |prop| 51 | switchesValue += " /property:#{prop}" 52 | end 53 | 54 | extraSwitches = attributes.fetch(:extraSwitches, []) 55 | 56 | extraSwitches.each do |switch| 57 | switchesValue += " /#{switch}" 58 | end 59 | 60 | targets = attributes.fetch(:targets, []) 61 | targetsValue = "" 62 | targets.each do |target| 63 | targetsValue += " /t:#{target}" 64 | end 65 | 66 | Kernel::system("#{msbuildFile} #{projFile} #{targetsValue} #{switchesValue}") 67 | end 68 | end 69 | 70 | class AspNetCompilerRunner 71 | def self.compile(attributes) 72 | 73 | webPhysDir = attributes.fetch(:webPhysDir, '') 74 | webVirDir = attributes.fetch(:webVirDir, 'This_Value_Is_Not_Used') 75 | 76 | frameworkDir = File.join(ENV['windir'].dup, 'Microsoft.NET', 'Framework', 'v4.0.30319') 77 | aspNetCompiler = File.join(frameworkDir, 'aspnet_compiler.exe') 78 | 79 | Kernel::system("#{aspNetCompiler} -nologo -errorstack -c -p #{webPhysDir} -v #{webVirDir}") 80 | end 81 | end 82 | 83 | class AsmInfoBuilder 84 | attr_reader :buildnumber 85 | 86 | def initialize(baseVersion, properties) 87 | @properties = properties; 88 | 89 | @buildnumber = baseVersion + (ENV["CCNetLabel"].nil? ? '0' : ENV["CCNetLabel"].to_s) 90 | @properties['Version'] = @properties['InformationalVersion'] = buildnumber; 91 | end 92 | 93 | 94 | 95 | def write(file) 96 | template = %q{ 97 | using System; 98 | using System.Reflection; 99 | using System.Runtime.InteropServices; 100 | 101 | <% @properties.each {|k, v| %> 102 | [assembly: Assembly<%=k%>Attribute("<%=v%>")] 103 | <% } %> 104 | }.gsub(/^ /, '') 105 | 106 | erb = ERB.new(template, 0, "%<>") 107 | 108 | File.open(file, 'w') do |file| 109 | file.puts erb.result(binding) 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /build_support/util.rb: -------------------------------------------------------------------------------- 1 | def waitfor(&block) 2 | checks = 0 3 | 4 | until block.call || checks >10 5 | sleep 0.5 6 | checks += 1 7 | end 8 | 9 | raise 'Waitfor timeout expired. Make sure that you aren\'t running something from the build output folders, or that you have browsed to it through Explorer.' if checks > 10 10 | end 11 | 12 | def get_commit_hash_and_date 13 | begin 14 | commit = `git log -1 --pretty=format:%H` 15 | git_date = `git log -1 --date=iso --pretty=format:%ad` 16 | commit_date = DateTime.parse( git_date ).strftime("%Y-%m-%d %H%M%S") 17 | rescue 18 | commit = "git unavailable" 19 | end 20 | 21 | [commit, commit_date] 22 | end -------------------------------------------------------------------------------- /build_support/versioning.rb: -------------------------------------------------------------------------------- 1 | require 'semver' 2 | 3 | def commit_data 4 | begin 5 | commit = `git rev-parse --short HEAD`.chomp()[0,6] 6 | git_date = `git log -1 --date=iso --pretty=format:%ad` 7 | commit_date = DateTime.parse( git_date ).strftime("%Y-%m-%d %H%M%S") 8 | rescue Exception => e 9 | puts e.inspect 10 | commit = (ENV['BUILD_VCS_NUMBER'] || "000000")[0,6] 11 | commit_date = Time.new.strftime("%Y-%m-%d %H%M%S") 12 | end 13 | [commit, commit_date] 14 | end 15 | 16 | task :versioning do 17 | ver = SemVer.find 18 | revision = (ENV['BUILD_NUMBER'] || ver.patch).to_i 19 | var = SemVer.new(ver.major, ver.minor, revision, ver.special) 20 | 21 | # extensible number w/ git hash 22 | ENV['BUILD_VERSION'] = BUILD_VERSION = ver.format("%M.%m.%p%s") + ".#{commit_data()[0]}" 23 | 24 | # nuget (not full semver 2.0.0-rc.1 support) see http://nuget.codeplex.com/workitem/1796 25 | ENV['NUGET_VERSION'] = NUGET_VERSION = ver.format("%M.%m.%p%s") 26 | 27 | # purely M.m.p format 28 | ENV['FORMAL_VERSION'] = FORMAL_VERSION = "#{ SemVer.new(ver.major, ver.minor, revision).format "%M.%m.%p"}" 29 | puts "##teamcity[buildNumber '#{BUILD_VERSION}']" # tell teamcity our decision 30 | end -------------------------------------------------------------------------------- /rakefile.rb: -------------------------------------------------------------------------------- 1 | COPYRIGHT = "Copyright 2012-2013 Chris Patterson, Albert Hives." 2 | 3 | require File.dirname(__FILE__) + "/build_support/BuildUtils.rb" 4 | require File.dirname(__FILE__) + "/build_support/util.rb" 5 | include FileTest 6 | require 'albacore' 7 | require File.dirname(__FILE__) + "/build_support/versioning.rb" 8 | 9 | PRODUCT = 'MassTransit-Quartz' 10 | CLR_TOOLS_VERSION = 'v4.0.30319' 11 | OUTPUT_PATH = 'bin/Release' 12 | 13 | props = { 14 | :src => File.expand_path("src"), 15 | :nuget => File.join(File.expand_path("src"), ".nuget", "nuget.exe"), 16 | :output => File.expand_path("build_output"), 17 | :artifacts => File.expand_path("build_artifacts"), 18 | :lib => File.expand_path("lib"), 19 | :projects => ["MassTransit-Quartz"], 20 | :keyfile => File.expand_path("MassTransit.snk") 21 | } 22 | 23 | desc "Cleans, compiles, il-merges, unit tests, prepares examples, packages zip" 24 | task :all => [:default, :package] 25 | 26 | desc "**Default**, compiles and runs tests" 27 | task :default => [:clean, :nuget_restore, :compile, :package] 28 | 29 | desc "Update the common version information for the build. You can call this task without building." 30 | assemblyinfo :global_version => [:versioning] do |asm| 31 | # Assembly file config 32 | asm.product_name = PRODUCT 33 | asm.description = "MassTransit-Quartz provides message scheduling for MassTransit services." 34 | asm.version = FORMAL_VERSION 35 | asm.file_version = FORMAL_VERSION 36 | asm.custom_attributes :AssemblyInformationalVersion => "#{BUILD_VERSION}", 37 | :ComVisibleAttribute => false, 38 | :CLSCompliantAttribute => true 39 | asm.copyright = COPYRIGHT 40 | asm.output_file = 'src/SolutionVersion.cs' 41 | asm.namespaces "System", "System.Reflection", "System.Runtime.InteropServices" 42 | end 43 | 44 | desc "Prepares the working directory for a new build" 45 | task :clean do 46 | FileUtils.rm_rf props[:output] 47 | waitfor { !exists?(props[:output]) } 48 | 49 | FileUtils.rm_rf props[:artifacts] 50 | waitfor { !exists?(props[:artifacts]) } 51 | 52 | Dir.mkdir props[:output] 53 | Dir.mkdir props[:artifacts] 54 | end 55 | 56 | desc "Cleans, versions, compiles the application and generates build_output/." 57 | task :compile => [:versioning, :global_version, :build4, :tests4, :copy4] 58 | 59 | task :copy35 => [:build35] do 60 | copyOutputFiles File.join(props[:src], "MassTransit.Scheduling/bin/Release/v3.5"), "MassTransit.Scheduling.{dll,pdb,xml}", File.join(props[:output], 'Scheduling', 'net-3.5') 61 | end 62 | 63 | task :copy4 => [:build4] do 64 | copyOutputFiles File.join(props[:src], "MassTransit.Scheduling/bin/Release"), "MassTransit.Scheduling.{dll,pdb,xml}", File.join(props[:output], 'Scheduling', 'net-4.0-full') 65 | copyOutputFiles File.join(props[:src], "MassTransit.QuartzIntegration/bin/Release"), "MassTransit.QuartzIntegration.{dll,pdb,xml}", File.join(props[:output], 'Integration', 'net-4.0-full') 66 | 67 | copyOutputFiles File.join(props[:src], "MassTransit.QuartzService/bin/Release"), "MassTransit.QuartzService.exe", File.join(props[:output], 'Service') 68 | copyOutputFiles File.join(props[:src], "MassTransit.QuartzService/bin/Release"), "*.dll", File.join(props[:output], 'Service') 69 | copyOutputFiles File.join(props[:src], "MassTransit.QuartzService/bin/Release"), "*.config", File.join(props[:output], 'Service') 70 | end 71 | 72 | desc "Only compiles the application." 73 | msbuild :build4 do |msb| 74 | msb.properties :Configuration => "Release", 75 | :Platform => 'Any CPU' 76 | msb.use :net4 77 | msb.targets :Rebuild 78 | msb.properties[:SignAssembly] = 'true' 79 | msb.properties[:AssemblyOriginatorKeyFile] = props[:keyfile] 80 | msb.solution = 'src/MassTransit.Quartz.sln' 81 | end 82 | 83 | def copyOutputFiles(fromDir, filePattern, outDir) 84 | FileUtils.mkdir_p outDir unless exists?(outDir) 85 | Dir.glob(File.join(fromDir, filePattern)){|file| 86 | copy(file, outDir) if File.file?(file) 87 | } 88 | end 89 | 90 | desc "Runs unit tests" 91 | nunit :tests4 => [:build4] do |nunit| 92 | nunit.command = File.join('src', 'packages','NUnit.Runners.2.6.3', 'tools', 'nunit-console.exe') 93 | nunit.parameters = "/framework=#{CLR_TOOLS_VERSION}", '/nothread', '/nologo', '/labels', "\"/xml=#{File.join(props[:artifacts], 'nunit-test-results-net-4.0.xml')}\"" 94 | nunit.assemblies = FileList[File.join(props[:src], "MassTransit.QuartzIntegration.Tests/bin/Release", "MassTransit.QuartzIntegration.Tests.dll")] 95 | end 96 | 97 | task :package => [:nuget, :zip_output] 98 | 99 | desc "ZIPs up the build results." 100 | zip :zip_output => [:versioning] do |zip| 101 | zip.directories_to_zip = [props[:output]] 102 | zip.output_file = "MassTransit-Quartz-#{NUGET_VERSION}.zip" 103 | zip.output_path = props[:artifacts] 104 | end 105 | 106 | desc "restores missing packages" 107 | msbuild :nuget_restore do |msb| 108 | msb.properties :SolutionDir => "../" 109 | msb.use :net4 110 | msb.targets :RestorePackages 111 | msb.solution = File.join(props[:src], "MassTransit.Scheduling", "MassTransit.Scheduling.csproj") 112 | end 113 | 114 | desc "Builds the nuget package" 115 | task :nuget => [:versioning, :create_nuspec] do 116 | sh "#{props[:nuget]} pack #{props[:artifacts]}/MassTransit.Scheduling.nuspec /Symbols /OutputDirectory #{props[:artifacts]}" 117 | sh "#{props[:nuget]} pack #{props[:artifacts]}/MassTransit.QuartzIntegration.nuspec /Symbols /OutputDirectory #{props[:artifacts]}" 118 | end 119 | 120 | nuspec :create_nuspec do |nuspec| 121 | nuspec.id = 'MassTransit.Scheduling' 122 | nuspec.version = NUGET_VERSION 123 | nuspec.authors = 'Chris Patterson, Albert Hives' 124 | nuspec.summary = 'Scheduled messaging for MassTransit' 125 | nuspec.description = 'MassTransit Scheduling is used to schedule future message delivery' 126 | nuspec.title = 'MassTransit.Scheduling' 127 | nuspec.projectUrl = 'http://github.com/MassTransit/MassTransit-Quartz' 128 | nuspec.iconUrl = 'http://MassTransit-project.com/wp-content/themes/pandora/slide.1.png' 129 | nuspec.language = "en-US" 130 | nuspec.licenseUrl = "http://www.apache.org/licenses/LICENSE-2.0" 131 | nuspec.requireLicenseAcceptance = "false" 132 | nuspec.dependency "Magnum", "2.1.3" 133 | nuspec.dependency "MassTransit", "2.10.2" 134 | nuspec.output_file = File.join(props[:artifacts], 'MassTransit.Scheduling.nuspec') 135 | add_files File.join(props[:output], 'Scheduling'), 'MassTransit.Scheduling.{dll,pdb,xml}', nuspec 136 | nuspec.file(File.join(props[:src], "MassTransit.Scheduling\\**\\*.cs").gsub("/","\\"), "src") 137 | end 138 | 139 | nuspec :create_nuspec do |nuspec| 140 | nuspec.id = 'MassTransit.QuartzIntegration' 141 | nuspec.version = NUGET_VERSION 142 | nuspec.authors = 'Chris Patterson, Albert Hives' 143 | nuspec.summary = 'Quartz integration for MassTransit' 144 | nuspec.description = 'Adds support for Quartz as a message scheduler to MassTransit (used by the MassTransit.QuartzService project)' 145 | nuspec.title = 'MassTransit.QuartzIntegration' 146 | nuspec.projectUrl = 'http://github.com/MassTransit/MassTransit-Quartz' 147 | nuspec.iconUrl = 'http://MassTransit-project.com/wp-content/themes/pandora/slide.1.png' 148 | nuspec.language = "en-US" 149 | nuspec.licenseUrl = "http://www.apache.org/licenses/LICENSE-2.0" 150 | nuspec.requireLicenseAcceptance = "false" 151 | nuspec.dependency "Magnum", "2.1.3" 152 | nuspec.dependency "MassTransit", "2.10.2" 153 | nuspec.dependency "MassTransit.Scheduling", NUGET_VERSION 154 | nuspec.dependency "Common.Logging", "3.0.0" 155 | nuspec.dependency "Newtonsoft.Json", "6.0.6" 156 | nuspec.dependency "Quartz", "2.3.2" 157 | nuspec.output_file = File.join(props[:artifacts], 'MassTransit.QuartzIntegration.nuspec') 158 | add_files File.join(props[:output], 'Integration'), 'MassTransit.QuartzIntegration.{dll,pdb,xml}', nuspec 159 | nuspec.file(File.join(props[:src], "MassTransit.QuartzIntegration\\**\\*.cs").gsub("/","\\"), "src") 160 | end 161 | 162 | def project_outputs(props) 163 | props[:projects].map{ |p| "src/#{p}/bin/#{BUILD_CONFIG}/#{p}.dll" }. 164 | concat( props[:projects].map{ |p| "src/#{p}/bin/#{BUILD_CONFIG}/#{p}.exe" } ). 165 | find_all{ |path| exists?(path) } 166 | end 167 | 168 | def get_commit_hash_and_date 169 | begin 170 | commit = `git log -1 --pretty=format:%H` 171 | git_date = `git log -1 --date=iso --pretty=format:%ad` 172 | commit_date = DateTime.parse( git_date ).strftime("%Y-%m-%d %H%M%S") 173 | rescue 174 | commit = "git unavailable" 175 | end 176 | 177 | [commit, commit_date] 178 | end 179 | 180 | def add_files stage, what_dlls, nuspec 181 | [['net35', 'net-3.5'], ['net40', 'net-4.0'], ['net40-full', 'net-4.0-full']].each{|fw| 182 | takeFrom = File.join(stage, fw[1], what_dlls) 183 | Dir.glob(takeFrom).each do |f| 184 | nuspec.file(f.gsub("/", "\\"), "lib\\#{fw[0]}") 185 | end 186 | } 187 | end 188 | 189 | def waitfor(&block) 190 | checks = 0 191 | 192 | until block.call || checks >10 193 | sleep 0.5 194 | checks += 1 195 | end 196 | 197 | raise 'Waitfor timeout expired. Make sure that you aren\'t running something from the build output folders, or that you have browsed to it through Explorer.' if checks > 10 198 | end 199 | -------------------------------------------------------------------------------- /setup_sql_server.sql: -------------------------------------------------------------------------------- 1 | --# thanks to George Papastamatopoulos for submitting this ... and Marko Lahma for 2 | --# updating it. 3 | 4 | USE [quartz] 5 | GO 6 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) 7 | ALTER TABLE [dbo].[QRTZ_TRIGGERS] DROP CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS 8 | GO 9 | 10 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) 11 | ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] DROP CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS 12 | GO 13 | 14 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) 15 | ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS 16 | GO 17 | 18 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) 19 | ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS 20 | GO 21 | 22 | IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QRTZ_JOB_LISTENERS_QRTZ_JOB_DETAILS]') AND parent_object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_LISTENERS]')) 23 | ALTER TABLE [dbo].[QRTZ_JOB_LISTENERS] DROP CONSTRAINT [FK_QRTZ_JOB_LISTENERS_QRTZ_JOB_DETAILS] 24 | 25 | IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGER_LISTENERS_QRTZ_TRIGGERS]') AND parent_object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGER_LISTENERS]')) 26 | ALTER TABLE [dbo].[QRTZ_TRIGGER_LISTENERS] DROP CONSTRAINT [FK_QRTZ_TRIGGER_LISTENERS_QRTZ_TRIGGERS] 27 | 28 | 29 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 30 | DROP TABLE [dbo].[QRTZ_CALENDARS] 31 | GO 32 | 33 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 34 | DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS] 35 | GO 36 | 37 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 38 | DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS] 39 | GO 40 | 41 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 42 | DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS] 43 | GO 44 | 45 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 46 | DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] 47 | GO 48 | 49 | IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_LISTENERS]') AND type in (N'U')) 50 | DROP TABLE [dbo].[QRTZ_JOB_LISTENERS] 51 | 52 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 53 | DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE] 54 | GO 55 | 56 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 57 | DROP TABLE [dbo].[QRTZ_LOCKS] 58 | GO 59 | IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGER_LISTENERS]') AND type in (N'U')) 60 | DROP TABLE [dbo].[QRTZ_TRIGGER_LISTENERS] 61 | 62 | 63 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 64 | DROP TABLE [dbo].[QRTZ_JOB_DETAILS] 65 | GO 66 | 67 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 68 | DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] 69 | GO 70 | 71 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 72 | DROP TABLE [dbo].QRTZ_SIMPROP_TRIGGERS 73 | GO 74 | 75 | IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) 76 | DROP TABLE [dbo].[QRTZ_TRIGGERS] 77 | GO 78 | 79 | CREATE TABLE [dbo].[QRTZ_CALENDARS] ( 80 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 81 | [CALENDAR_NAME] [NVARCHAR] (200) NOT NULL , 82 | [CALENDAR] [IMAGE] NOT NULL 83 | ) ON [PRIMARY] 84 | GO 85 | 86 | CREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] ( 87 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 88 | [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , 89 | [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , 90 | [CRON_EXPRESSION] [NVARCHAR] (120) NOT NULL , 91 | [TIME_ZONE_ID] [NVARCHAR] (80) 92 | ) ON [PRIMARY] 93 | GO 94 | 95 | CREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] ( 96 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 97 | [ENTRY_ID] [NVARCHAR] (95) NOT NULL , 98 | [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , 99 | [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , 100 | [INSTANCE_NAME] [NVARCHAR] (200) NOT NULL , 101 | [FIRED_TIME] [BIGINT] NOT NULL , 102 | [PRIORITY] [INTEGER] NOT NULL , 103 | [STATE] [NVARCHAR] (16) NOT NULL, 104 | [JOB_NAME] [NVARCHAR] (150) NULL , 105 | [JOB_GROUP] [NVARCHAR] (150) NULL , 106 | [IS_NONCONCURRENT] BIT NULL , 107 | [REQUESTS_RECOVERY] BIT NULL 108 | ) ON [PRIMARY] 109 | GO 110 | 111 | CREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] ( 112 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 113 | [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL 114 | ) ON [PRIMARY] 115 | GO 116 | 117 | CREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] ( 118 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 119 | [INSTANCE_NAME] [NVARCHAR] (200) NOT NULL , 120 | [LAST_CHECKIN_TIME] [BIGINT] NOT NULL , 121 | [CHECKIN_INTERVAL] [BIGINT] NOT NULL 122 | ) ON [PRIMARY] 123 | GO 124 | 125 | CREATE TABLE [dbo].[QRTZ_LOCKS] ( 126 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 127 | [LOCK_NAME] [NVARCHAR] (40) NOT NULL 128 | ) ON [PRIMARY] 129 | GO 130 | 131 | CREATE TABLE [dbo].[QRTZ_JOB_DETAILS] ( 132 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 133 | [JOB_NAME] [NVARCHAR] (150) NOT NULL , 134 | [JOB_GROUP] [NVARCHAR] (150) NOT NULL , 135 | [DESCRIPTION] [NVARCHAR] (250) NULL , 136 | [JOB_CLASS_NAME] [NVARCHAR] (250) NOT NULL , 137 | [IS_DURABLE] BIT NOT NULL , 138 | [IS_NONCONCURRENT] BIT NOT NULL , 139 | [IS_UPDATE_DATA] BIT NOT NULL , 140 | [REQUESTS_RECOVERY] BIT NOT NULL , 141 | [JOB_DATA] [IMAGE] NULL 142 | ) ON [PRIMARY] 143 | GO 144 | 145 | CREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ( 146 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 147 | [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , 148 | [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , 149 | [REPEAT_COUNT] [INTEGER] NOT NULL , 150 | [REPEAT_INTERVAL] [BIGINT] NOT NULL , 151 | [TIMES_TRIGGERED] [INTEGER] NOT NULL 152 | ) ON [PRIMARY] 153 | GO 154 | 155 | CREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ( 156 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 157 | [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , 158 | [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , 159 | [STR_PROP_1] [NVARCHAR] (512) NULL, 160 | [STR_PROP_2] [NVARCHAR] (512) NULL, 161 | [STR_PROP_3] [NVARCHAR] (512) NULL, 162 | [INT_PROP_1] [INT] NULL, 163 | [INT_PROP_2] [INT] NULL, 164 | [LONG_PROP_1] [BIGINT] NULL, 165 | [LONG_PROP_2] [BIGINT] NULL, 166 | [DEC_PROP_1] [NUMERIC] (13,4) NULL, 167 | [DEC_PROP_2] [NUMERIC] (13,4) NULL, 168 | [BOOL_PROP_1] BIT NULL, 169 | [BOOL_PROP_2] BIT NULL, 170 | ) ON [PRIMARY] 171 | GO 172 | 173 | CREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] ( 174 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 175 | [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , 176 | [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , 177 | [BLOB_DATA] [IMAGE] NULL 178 | ) ON [PRIMARY] 179 | GO 180 | 181 | CREATE TABLE [dbo].[QRTZ_TRIGGERS] ( 182 | [SCHED_NAME] [NVARCHAR] (100) NOT NULL , 183 | [TRIGGER_NAME] [NVARCHAR] (150) NOT NULL , 184 | [TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL , 185 | [JOB_NAME] [NVARCHAR] (150) NOT NULL , 186 | [JOB_GROUP] [NVARCHAR] (150) NOT NULL , 187 | [DESCRIPTION] [NVARCHAR] (250) NULL , 188 | [NEXT_FIRE_TIME] [BIGINT] NULL , 189 | [PREV_FIRE_TIME] [BIGINT] NULL , 190 | [PRIORITY] [INTEGER] NULL , 191 | [TRIGGER_STATE] [NVARCHAR] (16) NOT NULL , 192 | [TRIGGER_TYPE] [NVARCHAR] (8) NOT NULL , 193 | [START_TIME] [BIGINT] NOT NULL , 194 | [END_TIME] [BIGINT] NULL , 195 | [CALENDAR_NAME] [NVARCHAR] (200) NULL , 196 | [MISFIRE_INSTR] [INTEGER] NULL , 197 | [JOB_DATA] [IMAGE] NULL 198 | ) ON [PRIMARY] 199 | GO 200 | 201 | ALTER TABLE [dbo].[QRTZ_CALENDARS] WITH NOCHECK ADD 202 | CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY CLUSTERED 203 | ( 204 | [SCHED_NAME], 205 | [CALENDAR_NAME] 206 | ) ON [PRIMARY] 207 | GO 208 | 209 | ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] WITH NOCHECK ADD 210 | CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY CLUSTERED 211 | ( 212 | [SCHED_NAME], 213 | [TRIGGER_NAME], 214 | [TRIGGER_GROUP] 215 | ) ON [PRIMARY] 216 | GO 217 | 218 | ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] WITH NOCHECK ADD 219 | CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY CLUSTERED 220 | ( 221 | [SCHED_NAME], 222 | [ENTRY_ID] 223 | ) ON [PRIMARY] 224 | GO 225 | 226 | ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD 227 | CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED 228 | ( 229 | [SCHED_NAME], 230 | [TRIGGER_GROUP] 231 | ) ON [PRIMARY] 232 | GO 233 | 234 | ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] WITH NOCHECK ADD 235 | CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY CLUSTERED 236 | ( 237 | [SCHED_NAME], 238 | [INSTANCE_NAME] 239 | ) ON [PRIMARY] 240 | GO 241 | 242 | ALTER TABLE [dbo].[QRTZ_LOCKS] WITH NOCHECK ADD 243 | CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY CLUSTERED 244 | ( 245 | [SCHED_NAME], 246 | [LOCK_NAME] 247 | ) ON [PRIMARY] 248 | GO 249 | 250 | ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] WITH NOCHECK ADD 251 | CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY CLUSTERED 252 | ( 253 | [SCHED_NAME], 254 | [JOB_NAME], 255 | [JOB_GROUP] 256 | ) ON [PRIMARY] 257 | GO 258 | 259 | ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] WITH NOCHECK ADD 260 | CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED 261 | ( 262 | [SCHED_NAME], 263 | [TRIGGER_NAME], 264 | [TRIGGER_GROUP] 265 | ) ON [PRIMARY] 266 | GO 267 | 268 | ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] WITH NOCHECK ADD 269 | CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED 270 | ( 271 | [SCHED_NAME], 272 | [TRIGGER_NAME], 273 | [TRIGGER_GROUP] 274 | ) ON [PRIMARY] 275 | GO 276 | 277 | ALTER TABLE [dbo].[QRTZ_TRIGGERS] WITH NOCHECK ADD 278 | CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY CLUSTERED 279 | ( 280 | [SCHED_NAME], 281 | [TRIGGER_NAME], 282 | [TRIGGER_GROUP] 283 | ) ON [PRIMARY] 284 | GO 285 | 286 | ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD 287 | CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY 288 | ( 289 | [SCHED_NAME], 290 | [TRIGGER_NAME], 291 | [TRIGGER_GROUP] 292 | ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( 293 | [SCHED_NAME], 294 | [TRIGGER_NAME], 295 | [TRIGGER_GROUP] 296 | ) ON DELETE CASCADE 297 | GO 298 | 299 | ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD 300 | CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY 301 | ( 302 | [SCHED_NAME], 303 | [TRIGGER_NAME], 304 | [TRIGGER_GROUP] 305 | ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( 306 | [SCHED_NAME], 307 | [TRIGGER_NAME], 308 | [TRIGGER_GROUP] 309 | ) ON DELETE CASCADE 310 | GO 311 | 312 | ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD 313 | CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY 314 | ( 315 | [SCHED_NAME], 316 | [TRIGGER_NAME], 317 | [TRIGGER_GROUP] 318 | ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( 319 | [SCHED_NAME], 320 | [TRIGGER_NAME], 321 | [TRIGGER_GROUP] 322 | ) ON DELETE CASCADE 323 | GO 324 | 325 | ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD 326 | CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY 327 | ( 328 | [SCHED_NAME], 329 | [JOB_NAME], 330 | [JOB_GROUP] 331 | ) REFERENCES [dbo].[QRTZ_JOB_DETAILS] ( 332 | [SCHED_NAME], 333 | [JOB_NAME], 334 | [JOB_GROUP] 335 | ) 336 | GO 337 | 338 | CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP) 339 | CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP) 340 | CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME) 341 | CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP) 342 | CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE) 343 | CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE) 344 | CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE) 345 | CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME) 346 | CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME) 347 | CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME) 348 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE) 349 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE) 350 | 351 | CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME) 352 | CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY) 353 | CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP) 354 | CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP) 355 | CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 356 | CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP) 357 | GO -------------------------------------------------------------------------------- /src/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | true 8 | 9 | 10 | false 11 | 12 | 13 | false 14 | 15 | 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 27 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) 28 | 29 | 30 | 31 | 32 | $(SolutionDir).nuget 33 | packages.config 34 | 35 | 36 | 37 | 38 | $(NuGetToolsPath)\nuget.exe 39 | @(PackageSource) 40 | 41 | "$(NuGetExePath)" 42 | mono --runtime=v4.0.30319 $(NuGetExePath) 43 | 44 | $(TargetDir.Trim('\\')) 45 | 46 | -RequireConsent 47 | 48 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(RequireConsentSwitch) -solutionDir "$(SolutionDir) " 49 | $(NuGetCommand) pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols 50 | 51 | 52 | 53 | RestorePackages; 54 | $(ResolveReferencesDependsOn); 55 | 56 | 57 | 58 | 59 | $(BuildDependsOn); 60 | BuildPackage; 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /src/.nuget/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/MassTransit.Quartz.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassTransit.QuartzIntegration", "MassTransit.QuartzIntegration\MassTransit.QuartzIntegration.csproj", "{2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C9CDA928-0CFE-4861-BA77-2BBC79981109}" 9 | ProjectSection(SolutionItems) = preProject 10 | .nuget\NuGet.Config = .nuget\NuGet.Config 11 | .nuget\NuGet.exe = .nuget\NuGet.exe 12 | .nuget\NuGet.targets = .nuget\NuGet.targets 13 | .nuget\packages.config = .nuget\packages.config 14 | EndProjectSection 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassTransit.Scheduling", "MassTransit.Scheduling\MassTransit.Scheduling.csproj", "{863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassTransit.QuartzIntegration.Tests", "MassTransit.QuartzIntegration.Tests\MassTransit.QuartzIntegration.Tests.csproj", "{CC243B02-0542-48CB-B175-C8035075E376}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassTransit.QuartzService", "MassTransit.QuartzService\MassTransit.QuartzService.csproj", "{989BA511-C126-4C88-A74B-BAD83DF2291B}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Debug|Mixed Platforms = Debug|Mixed Platforms 26 | Debug|x86 = Debug|x86 27 | Release|Any CPU = Release|Any CPU 28 | Release|Mixed Platforms = Release|Mixed Platforms 29 | Release|x86 = Release|x86 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 35 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 36 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Debug|x86.ActiveCfg = Debug|Any CPU 37 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 40 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Release|Mixed Platforms.Build.0 = Release|Any CPU 41 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC}.Release|x86.ActiveCfg = Release|Any CPU 42 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 45 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 46 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Debug|x86.ActiveCfg = Debug|Any CPU 47 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 50 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Release|Mixed Platforms.Build.0 = Release|Any CPU 51 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00}.Release|x86.ActiveCfg = Release|Any CPU 52 | {CC243B02-0542-48CB-B175-C8035075E376}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {CC243B02-0542-48CB-B175-C8035075E376}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {CC243B02-0542-48CB-B175-C8035075E376}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 55 | {CC243B02-0542-48CB-B175-C8035075E376}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 56 | {CC243B02-0542-48CB-B175-C8035075E376}.Debug|x86.ActiveCfg = Debug|Any CPU 57 | {CC243B02-0542-48CB-B175-C8035075E376}.Release|Any CPU.ActiveCfg = Release|Any CPU 58 | {CC243B02-0542-48CB-B175-C8035075E376}.Release|Any CPU.Build.0 = Release|Any CPU 59 | {CC243B02-0542-48CB-B175-C8035075E376}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 60 | {CC243B02-0542-48CB-B175-C8035075E376}.Release|Mixed Platforms.Build.0 = Release|Any CPU 61 | {CC243B02-0542-48CB-B175-C8035075E376}.Release|x86.ActiveCfg = Release|Any CPU 62 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 63 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Debug|Any CPU.Build.0 = Debug|Any CPU 64 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 65 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Debug|Mixed Platforms.Build.0 = Debug|x86 66 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Debug|x86.ActiveCfg = Debug|x86 67 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Debug|x86.Build.0 = Debug|x86 68 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Release|Any CPU.ActiveCfg = Release|Any CPU 69 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Release|Any CPU.Build.0 = Release|Any CPU 70 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 71 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Release|Mixed Platforms.Build.0 = Release|Any CPU 72 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Release|x86.ActiveCfg = Release|x86 73 | {989BA511-C126-4C88-A74B-BAD83DF2291B}.Release|x86.Build.0 = Release|x86 74 | EndGlobalSection 75 | GlobalSection(SolutionProperties) = preSolution 76 | HideSolutionNode = FALSE 77 | EndGlobalSection 78 | EndGlobal 79 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/ContextSetup.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration.Tests 14 | { 15 | using Log4NetIntegration.Logging; 16 | using NUnit.Framework; 17 | using log4net; 18 | 19 | 20 | [SetUpFixture] 21 | public class ContextSetup 22 | { 23 | [SetUp] 24 | public void Before_any_tests() 25 | { 26 | Log4NetLogger.Use("log4net.config"); 27 | } 28 | 29 | [TearDown] 30 | public void After_all_tests() 31 | { 32 | LogManager.Shutdown(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/JobDetail_Specs.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzIntegration.Tests 2 | { 3 | using System.Threading; 4 | using Magnum.Extensions; 5 | using NUnit.Framework; 6 | using Quartz; 7 | using Quartz.Impl; 8 | using Quartz.Simpl; 9 | 10 | 11 | [TestFixture] 12 | public class When_scheduling_a_job_using_quartz 13 | { 14 | 15 | [Test] 16 | public void Should_return_the_properties() 17 | { 18 | var factory = new StdSchedulerFactory(); 19 | var scheduler = factory.GetScheduler(); 20 | scheduler.Start(); 21 | 22 | IJobDetail jobDetail = JobBuilder.Create() 23 | .UsingJobData("Body", "By Jake") 24 | .Build(); 25 | 26 | ITrigger trigger = TriggerBuilder.Create() 27 | .ForJob(jobDetail) 28 | .StartAt(1.Seconds().FromUtcNow()) 29 | .Build(); 30 | 31 | scheduler.ScheduleJob(jobDetail, trigger); 32 | 33 | Assert.IsTrue(MyJob.Signaled.WaitOne(Utils.Timeout)); 34 | 35 | Assert.AreEqual("By Jake", MyJob.SignaledBody); 36 | } 37 | 38 | [Test] 39 | public void Should_return_the_properties_with_custom_factory() 40 | { 41 | var factory = new StdSchedulerFactory(); 42 | var scheduler = factory.GetScheduler(); 43 | scheduler.JobFactory = new MassTransitJobFactory(null); 44 | scheduler.Start(); 45 | 46 | IJobDetail jobDetail = JobBuilder.Create() 47 | .UsingJobData("Body", "By Jake") 48 | .Build(); 49 | 50 | ITrigger trigger = TriggerBuilder.Create() 51 | .ForJob(jobDetail) 52 | .StartAt(1.Seconds().FromUtcNow()) 53 | .Build(); 54 | 55 | scheduler.ScheduleJob(jobDetail, trigger); 56 | 57 | Assert.IsTrue(MyJob.Signaled.WaitOne(Utils.Timeout)); 58 | 59 | Assert.AreEqual("By Jake", MyJob.SignaledBody); 60 | } 61 | 62 | 63 | class MyJob : 64 | IJob 65 | { 66 | public static ManualResetEvent Signaled { get; private set; } 67 | public static string SignaledBody { get; private set; } 68 | 69 | static MyJob() 70 | { 71 | Signaled = new ManualResetEvent(false); 72 | } 73 | 74 | public void Execute(IJobExecutionContext context) 75 | { 76 | SignaledBody = Body; 77 | Signaled.Set(); 78 | } 79 | 80 | public string Body { get; set; } 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/MassTransit.QuartzIntegration.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {CC243B02-0542-48CB-B175-C8035075E376} 9 | Library 10 | Properties 11 | MassTransit.QuartzIntegration.Tests 12 | MassTransit.QuartzIntegration.Tests 13 | v4.0 14 | 512 15 | ..\ 16 | true 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll 38 | 39 | 40 | ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll 41 | 42 | 43 | False 44 | ..\packages\Common.Logging.Log4Net1211.3.0.0\lib\net40\Common.Logging.Log4Net1211.dll 45 | 46 | 47 | False 48 | ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll 49 | 50 | 51 | False 52 | ..\packages\Magnum.2.1.3\lib\NET40\Magnum.dll 53 | 54 | 55 | ..\packages\MassTransit.2.10.2\lib\net40\MassTransit.dll 56 | True 57 | 58 | 59 | ..\packages\MassTransit.Log4Net.2.10.2\lib\net40\MassTransit.Log4NetIntegration.dll 60 | True 61 | 62 | 63 | ..\packages\MassTransit.RabbitMQ.2.10.2\lib\net40\MassTransit.Transports.RabbitMq.dll 64 | True 65 | 66 | 67 | False 68 | ..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll 69 | 70 | 71 | False 72 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 73 | 74 | 75 | ..\packages\Quartz.2.3.2\lib\net40\Quartz.dll 76 | 77 | 78 | ..\packages\RabbitMQ.Client.3.4.3\lib\net35\RabbitMQ.Client.dll 79 | 80 | 81 | 82 | 83 | 84 | 85 | SolutionVersion.cs 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Designer 98 | 99 | 100 | PreserveNewest 101 | 102 | 103 | Designer 104 | 105 | 106 | 107 | 108 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC} 109 | MassTransit.QuartzIntegration 110 | 111 | 112 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00} 113 | MassTransit.Scheduling 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 128 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/PastEvent_Specs.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzIntegration.Tests 2 | { 3 | using System; 4 | using System.Threading; 5 | using Magnum.Extensions; 6 | using NUnit.Framework; 7 | using Quartz; 8 | using Quartz.Impl; 9 | using Scheduling; 10 | 11 | 12 | [TestFixture] 13 | public class Specifying_an_event_in_the_past 14 | { 15 | [Test] 16 | public void Should_properly_send_the_message() 17 | { 18 | _bus.ScheduleMessage((-1).Hours().FromUtcNow(), new A { Name = "Joe" }, x => 19 | { 20 | x.SetHeader("TestHeader", "Test"); 21 | }); 22 | 23 | Assert.IsTrue(_receivedA.WaitOne(Utils.Timeout), "Message A not handled"); 24 | 25 | Assert.IsTrue(_received.Headers["TestHeader"].Equals("Test")); 26 | } 27 | 28 | 29 | class A 30 | { 31 | public string Name { get; set; } 32 | } 33 | 34 | IScheduler _scheduler; 35 | IServiceBus _bus; 36 | ManualResetEvent _receivedA; 37 | IConsumeContext _received; 38 | 39 | [TestFixtureSetUp] 40 | public void Setup_quartz_service() 41 | { 42 | ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); 43 | _scheduler = schedulerFactory.GetScheduler(); 44 | 45 | _receivedA = new ManualResetEvent(false); 46 | 47 | _bus = ServiceBusFactory.New(x => 48 | { 49 | x.ReceiveFrom("loopback://localhost/quartz"); 50 | x.UseJsonSerializer(); 51 | 52 | x.Subscribe(s => 53 | { 54 | s.Handler((msg, context) => 55 | { 56 | _received = msg; 57 | _receivedA.Set(); 58 | }); 59 | s.Consumer(() => new ScheduleMessageConsumer(_scheduler)); 60 | }); 61 | }); 62 | 63 | _scheduler.JobFactory = new MassTransitJobFactory(_bus); 64 | _scheduler.Start(); 65 | } 66 | 67 | [TestFixtureTearDown] 68 | public void Teardown_quartz_service() 69 | { 70 | if (_scheduler != null) 71 | _scheduler.Standby(); 72 | if (_bus != null) 73 | _bus.Dispose(); 74 | if (_scheduler != null) 75 | _scheduler.Shutdown(); 76 | } 77 | } 78 | 79 | 80 | [TestFixture, Explicit] 81 | public class Sending_past_events_to_quartz 82 | { 83 | [Test] 84 | public void Should_properly_send_the_message() 85 | { 86 | _bus.ScheduleMessage((-1).Minutes().FromUtcNow(), new A { Name = "Joe" }, x => 87 | { 88 | x.SetHeader("TestHeader", "Test"); 89 | }); 90 | 91 | Assert.IsTrue(_receivedA.WaitOne(TimeSpan.FromMinutes(1)), "Message A not handled"); 92 | 93 | Assert.IsTrue(_received.Headers["TestHeader"].Equals("Test")); 94 | } 95 | 96 | [Test] 97 | public void Should_not_handle_now() 98 | { 99 | _bus.ScheduleMessage(DateTime.UtcNow, new A { Name = "Joe" }, x => 100 | { 101 | x.SetHeader("TestHeader", "Test"); 102 | }); 103 | 104 | Assert.IsTrue(_receivedA.WaitOne(Utils.Timeout), "Message A not handled"); 105 | 106 | Assert.IsTrue(_received.Headers["TestHeader"].Equals("Test")); 107 | } 108 | 109 | [Test] 110 | public void Should_send_a_future_message() 111 | { 112 | _bus.ScheduleMessage((1).Seconds().FromUtcNow(), new A { Name = "Joe" }, x => 113 | { 114 | x.SetHeader("TestHeader", "Test"); 115 | }); 116 | 117 | Assert.IsTrue(_receivedA.WaitOne(Utils.Timeout), "Message A not handled"); 118 | 119 | Assert.IsTrue(_received.Headers["TestHeader"].Equals("Test")); 120 | } 121 | 122 | 123 | class A 124 | { 125 | public string Name { get; set; } 126 | } 127 | 128 | IServiceBus _bus; 129 | ManualResetEvent _receivedA; 130 | IConsumeContext _received; 131 | 132 | [TestFixtureSetUp] 133 | public void Setup_quartz_service() 134 | { 135 | _receivedA = new ManualResetEvent(false); 136 | 137 | _bus = ServiceBusFactory.New(x => 138 | { 139 | x.ReceiveFrom("rabbitmq://localhost/test_quartz_client"); 140 | x.UseJsonSerializer(); 141 | x.UseRabbitMq(); 142 | 143 | x.Subscribe(s => 144 | { 145 | s.Handler((msg, context) => 146 | { 147 | _received = msg; 148 | _receivedA.Set(); 149 | }); 150 | }); 151 | }); 152 | 153 | } 154 | 155 | [TestFixtureTearDown] 156 | public void Teardown_quartz_service() 157 | { 158 | if (_bus != null) 159 | _bus.Dispose(); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/Service_Specs.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration.Tests 14 | { 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Linq; 18 | using System.Threading; 19 | using Magnum.Extensions; 20 | using NUnit.Framework; 21 | using Quartz; 22 | using Quartz.Impl; 23 | using Scheduling; 24 | 25 | 26 | [TestFixture] 27 | public class Using_the_quartz_service_with_json 28 | { 29 | [Test] 30 | public void Should_startup_properly() 31 | { 32 | _bus.ScheduleMessage(1.Seconds().FromUtcNow(), new A {Name = "Joe"}); 33 | 34 | Assert.IsTrue(_receivedA.WaitOne(Utils.Timeout), "Message A not handled"); 35 | Assert.IsTrue(_receivedIA.WaitOne(Utils.Timeout), "Message IA not handled"); 36 | } 37 | 38 | 39 | class A : IA 40 | { 41 | public string Name { get; set; } 42 | } 43 | 44 | 45 | class IA 46 | { 47 | string Id { get; set; } 48 | } 49 | 50 | 51 | IScheduler _scheduler; 52 | IServiceBus _bus; 53 | ManualResetEvent _receivedA; 54 | ManualResetEvent _receivedIA; 55 | 56 | [TestFixtureSetUp] 57 | public void Setup_quartz_service() 58 | { 59 | ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); 60 | _scheduler = schedulerFactory.GetScheduler(); 61 | 62 | _receivedA = new ManualResetEvent(false); 63 | _receivedIA = new ManualResetEvent(false); 64 | 65 | _bus = ServiceBusFactory.New(x => 66 | { 67 | x.ReceiveFrom("loopback://localhost/quartz"); 68 | x.UseJsonSerializer(); 69 | 70 | x.Subscribe(s => 71 | { 72 | s.Handler(msg => _receivedA.Set()); 73 | s.Handler(msg => _receivedIA.Set()); 74 | s.Consumer(() => new ScheduleMessageConsumer(_scheduler)); 75 | }); 76 | }); 77 | 78 | _scheduler.JobFactory = new MassTransitJobFactory(_bus); 79 | _scheduler.Start(); 80 | } 81 | 82 | [TestFixtureTearDown] 83 | public void Teardown_quartz_service() 84 | { 85 | if (_scheduler != null) 86 | _scheduler.Standby(); 87 | if (_bus != null) 88 | _bus.Dispose(); 89 | if (_scheduler != null) 90 | _scheduler.Shutdown(); 91 | } 92 | } 93 | 94 | 95 | [TestFixture] 96 | public class Using_the_quartz_service_with_xml 97 | { 98 | [Test] 99 | public void Should_startup_properly() 100 | { 101 | _bus.ScheduleMessage(1.Seconds().FromUtcNow(), new A {Name = "Joe"}); 102 | 103 | Assert.IsTrue(_receivedA.WaitOne(Utils.Timeout), "Message A not handled"); 104 | Assert.IsTrue(_receivedIA.WaitOne(Utils.Timeout), "Message IA not handled"); 105 | } 106 | 107 | 108 | class A : IA 109 | { 110 | public string Name { get; set; } 111 | } 112 | 113 | 114 | class IA 115 | { 116 | string Id { get; set; } 117 | } 118 | 119 | 120 | IScheduler _scheduler; 121 | IServiceBus _bus; 122 | ManualResetEvent _receivedA; 123 | ManualResetEvent _receivedIA; 124 | 125 | [TestFixtureSetUp] 126 | public void Setup_quartz_service() 127 | { 128 | ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); 129 | _scheduler = schedulerFactory.GetScheduler(); 130 | 131 | _receivedA = new ManualResetEvent(false); 132 | _receivedIA = new ManualResetEvent(false); 133 | 134 | _bus = ServiceBusFactory.New(x => 135 | { 136 | x.ReceiveFrom("loopback://localhost/quartz"); 137 | x.UseXmlSerializer(); 138 | 139 | x.Subscribe(s => 140 | { 141 | s.Handler(msg => _receivedA.Set()); 142 | s.Handler(msg => _receivedIA.Set()); 143 | s.Consumer(() => new ScheduleMessageConsumer(_scheduler)); 144 | }); 145 | }); 146 | 147 | _scheduler.JobFactory = new MassTransitJobFactory(_bus); 148 | _scheduler.Start(); 149 | } 150 | 151 | [TestFixtureTearDown] 152 | public void Teardown_quartz_service() 153 | { 154 | if (_scheduler != null) 155 | _scheduler.Standby(); 156 | if (_bus != null) 157 | _bus.Dispose(); 158 | if (_scheduler != null) 159 | _scheduler.Shutdown(); 160 | } 161 | } 162 | 163 | 164 | [TestFixture] 165 | public class Using_the_quartz_service_and_cancelling 166 | { 167 | [Test] 168 | public void Should_cancel_the_scheduled_message() 169 | { 170 | ScheduledMessage scheduledMessage = _bus.ScheduleMessage(8.Seconds().FromUtcNow(), 171 | new A {Name = "Joe"}); 172 | 173 | _bus.CancelScheduledMessage(scheduledMessage); 174 | 175 | Assert.IsFalse(_receivedA.WaitOne(Utils.Timeout), "Message A handled"); 176 | Assert.IsFalse(_receivedIA.WaitOne(1.Seconds()), "Message IA handled"); 177 | } 178 | 179 | 180 | class A : IA 181 | { 182 | public string Name { get; set; } 183 | } 184 | 185 | 186 | class IA 187 | { 188 | string Id { get; set; } 189 | } 190 | 191 | 192 | IScheduler _scheduler; 193 | IServiceBus _bus; 194 | ManualResetEvent _receivedA; 195 | ManualResetEvent _receivedIA; 196 | 197 | [TestFixtureSetUp] 198 | public void Setup_quartz_service() 199 | { 200 | ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); 201 | _scheduler = schedulerFactory.GetScheduler(); 202 | 203 | _receivedA = new ManualResetEvent(false); 204 | _receivedIA = new ManualResetEvent(false); 205 | 206 | _bus = ServiceBusFactory.New(x => 207 | { 208 | x.ReceiveFrom("loopback://localhost/quartz"); 209 | x.UseXmlSerializer(); 210 | x.SetConcurrentConsumerLimit(1); 211 | 212 | x.Subscribe(s => 213 | { 214 | s.Handler(msg => _receivedA.Set()); 215 | s.Handler(msg => _receivedIA.Set()); 216 | s.Consumer(() => new ScheduleMessageConsumer(_scheduler)); 217 | s.Consumer(() => new CancelScheduledMessageConsumer(_scheduler)); 218 | }); 219 | }); 220 | 221 | _scheduler.JobFactory = new MassTransitJobFactory(_bus); 222 | _scheduler.Start(); 223 | } 224 | 225 | [TestFixtureTearDown] 226 | public void Teardown_quartz_service() 227 | { 228 | if (_scheduler != null) 229 | _scheduler.Standby(); 230 | if (_bus != null) 231 | _bus.Dispose(); 232 | if (_scheduler != null) 233 | _scheduler.Shutdown(); 234 | } 235 | } 236 | 237 | [TestFixture] 238 | public class Using_the_quartz_service_with_headers 239 | { 240 | [Test] 241 | public void Should_not_loose_headers() 242 | { 243 | var headers = new KeyValuePair[0]; 244 | _bus.SubscribeContextHandler(ctx => 245 | { 246 | headers = ctx.Headers.ToArray(); 247 | _receivedA.Set(); 248 | }); 249 | 250 | _bus.ScheduleMessage(1.Seconds().FromUtcNow(), new A { Name = "Joe" }, 251 | ctx => 252 | { 253 | ctx.SetHeader("ATest", "AValue"); 254 | }); 255 | 256 | Assert.IsTrue(_receivedA.WaitOne(Utils.Timeout), "Message A not handled"); 257 | Assert.IsNotEmpty(headers, "No Headers were sent"); 258 | Assert.AreEqual("AValue", headers.First(h => h.Key == "ATest").Value); 259 | } 260 | 261 | 262 | 263 | class A 264 | { 265 | public string Name { get; set; } 266 | } 267 | 268 | 269 | 270 | IScheduler _scheduler; 271 | IServiceBus _bus; 272 | ManualResetEvent _receivedA; 273 | 274 | [TestFixtureSetUp] 275 | public void Setup_quartz_service() 276 | { 277 | ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); 278 | _scheduler = schedulerFactory.GetScheduler(); 279 | 280 | _receivedA = new ManualResetEvent(false); 281 | 282 | _bus = ServiceBusFactory.New(x => 283 | { 284 | x.ReceiveFrom("loopback://localhost/quartz"); 285 | x.UseJsonSerializer(); 286 | 287 | x.Subscribe(s => 288 | { 289 | s.Consumer(() => new ScheduleMessageConsumer(_scheduler)); 290 | }); 291 | }); 292 | 293 | _scheduler.JobFactory = new MassTransitJobFactory(_bus); 294 | _scheduler.Start(); 295 | } 296 | 297 | [TestFixtureTearDown] 298 | public void Teardown_quartz_service() 299 | { 300 | if (_scheduler != null) 301 | _scheduler.Standby(); 302 | if (_bus != null) 303 | _bus.Dispose(); 304 | if (_scheduler != null) 305 | _scheduler.Shutdown(); 306 | } 307 | } 308 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/Syntax_Specs.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration.Tests 14 | { 15 | using Magnum.Extensions; 16 | using NUnit.Framework; 17 | using Scheduling; 18 | 19 | 20 | [TestFixture] 21 | public class Syntax_Specs 22 | { 23 | [Test] 24 | public void Should_have_a_clean_syntax() 25 | { 26 | IServiceBus bus = ServiceBusFactory.New(x => x.ReceiveFrom("loopback://localhost/client")); 27 | using (bus) 28 | { 29 | ScheduledMessage scheduledMessage = bus.ScheduleMessage(5.Seconds().FromNow(), new A()); 30 | 31 | Assert.IsNotNull(scheduledMessage); 32 | } 33 | } 34 | 35 | 36 | class A 37 | { 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/Utils.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration.Tests 14 | { 15 | using System; 16 | using System.Diagnostics; 17 | 18 | 19 | public static class Utils 20 | { 21 | public static TimeSpan Timeout 22 | { 23 | get 24 | { 25 | if (Debugger.IsAttached) 26 | return TimeSpan.FromMinutes(10); 27 | 28 | return TimeSpan.FromSeconds(8); 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/log4net.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | q 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/CancelScheduledMessageConsumer.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using Logging; 16 | using Quartz; 17 | using Scheduling; 18 | 19 | 20 | public class CancelScheduledMessageConsumer : 21 | Consumes.Context 22 | { 23 | static readonly ILog _log = Logger.Get(); 24 | readonly IScheduler _scheduler; 25 | 26 | public CancelScheduledMessageConsumer(IScheduler scheduler) 27 | { 28 | _scheduler = scheduler; 29 | } 30 | 31 | public void Consume(IConsumeContext context) 32 | { 33 | bool unscheduledJob = _scheduler.UnscheduleJob(new TriggerKey(context.Message.TokenId.ToString("N"))); 34 | 35 | if (_log.IsDebugEnabled) 36 | { 37 | if (unscheduledJob) 38 | { 39 | _log.DebugFormat("CancelScheduledMessage: {0} at {1}", context.Message.TokenId, 40 | context.Message.Timestamp); 41 | } 42 | else 43 | _log.DebugFormat("CancelScheduledMessage: no message found {0}", context.Message.TokenId); 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/CancelScheduledTimeoutConsumer.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using Logging; 16 | using Quartz; 17 | using Services.Timeout.Messages; 18 | 19 | 20 | public class CancelScheduledTimeoutConsumer : 21 | Consumes.Context 22 | { 23 | static readonly ILog _log = Logger.Get(); 24 | readonly IScheduler _scheduler; 25 | 26 | public CancelScheduledTimeoutConsumer(IScheduler scheduler) 27 | { 28 | _scheduler = scheduler; 29 | } 30 | 31 | public void Consume(IConsumeContext context) 32 | { 33 | string triggerKey = context.Message.CorrelationId.ToString("N") + context.Message.Tag; 34 | 35 | bool unscheduledJob = _scheduler.UnscheduleJob(new TriggerKey(triggerKey)); 36 | 37 | if (_log.IsDebugEnabled) 38 | { 39 | if (unscheduledJob) 40 | { 41 | _log.DebugFormat("CancelScheduledMessage: {0}", triggerKey); 42 | 43 | context.Bus.Publish(new TimeoutCancelled 44 | { 45 | CorrelationId = context.Message.CorrelationId, 46 | Tag = context.Message.Tag, 47 | }); 48 | } 49 | else 50 | _log.DebugFormat("CancelScheduledMessage: no message found {0}", triggerKey); 51 | } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/MassTransit.QuartzIntegration.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC} 9 | Library 10 | Properties 11 | MassTransit.QuartzIntegration 12 | MassTransit.QuartzIntegration 13 | v4.0 14 | 512 15 | .\ 16 | true 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll 38 | 39 | 40 | ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll 41 | 42 | 43 | False 44 | ..\packages\Magnum.2.1.3\lib\NET40\Magnum.dll 45 | 46 | 47 | ..\packages\MassTransit.2.10.2\lib\net40\MassTransit.dll 48 | True 49 | 50 | 51 | False 52 | ..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll 53 | 54 | 55 | ..\packages\Quartz.2.3.2\lib\net40\Quartz.dll 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | SolutionVersion.cs 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | Designer 81 | 82 | 83 | Designer 84 | 85 | 86 | 87 | 88 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00} 89 | MassTransit.Scheduling 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 104 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/MassTransitJobFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using System; 16 | using System.Globalization; 17 | using System.Linq; 18 | using System.Linq.Expressions; 19 | using System.Reflection; 20 | using Magnum.Caching; 21 | using Magnum.Extensions; 22 | using Magnum.Reflection; 23 | using Quartz; 24 | using Quartz.Spi; 25 | 26 | 27 | public class MassTransitJobFactory : 28 | IJobFactory 29 | { 30 | readonly IServiceBus _bus; 31 | readonly Cache _typeFactories; 32 | 33 | public MassTransitJobFactory(IServiceBus bus) 34 | { 35 | _bus = bus; 36 | _typeFactories = new GenericTypeCache(typeof(MassTransitJobFactory<>), type => 37 | { 38 | Type genericType = typeof(MassTransitJobFactory<>).MakeGenericType(type); 39 | 40 | return (IJobFactory)Activator.CreateInstance(genericType, _bus); 41 | }); 42 | } 43 | 44 | public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) 45 | { 46 | IJobDetail jobDetail = bundle.JobDetail; 47 | if (jobDetail == null) 48 | throw new SchedulerException("JobDetail was null"); 49 | 50 | Type type = jobDetail.JobType; 51 | 52 | return _typeFactories[type].NewJob(bundle, scheduler); 53 | } 54 | 55 | public void ReturnJob(IJob job) 56 | { 57 | } 58 | } 59 | 60 | 61 | public class MassTransitJobFactory : 62 | IJobFactory 63 | where T : IJob 64 | { 65 | readonly IServiceBus _bus; 66 | readonly Func _factory; 67 | readonly Cache> _propertyCache; 68 | 69 | public MassTransitJobFactory(IServiceBus bus) 70 | { 71 | _bus = bus; 72 | _factory = CreateConstructor(); 73 | 74 | const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; 75 | 76 | _propertyCache = new DictionaryCache>(typeof(T).GetProperties(Flags) 77 | .Where(x => x.GetGetMethod(true) != null) 78 | .Where(x => x.GetSetMethod(true) != null) 79 | .Select(x => new FastProperty(x, Flags)) 80 | .ToDictionary(x => x.Property.Name)); 81 | } 82 | 83 | public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) 84 | { 85 | try 86 | { 87 | T job = _factory(_bus); 88 | 89 | var jobData = new JobDataMap(); 90 | jobData.PutAll(scheduler.Context); 91 | jobData.PutAll(bundle.JobDetail.JobDataMap); 92 | jobData.PutAll(bundle.Trigger.JobDataMap); 93 | 94 | SetObjectProperties(job, jobData); 95 | 96 | return job; 97 | } 98 | catch (Exception ex) 99 | { 100 | var sex = new SchedulerException(string.Format(CultureInfo.InvariantCulture, 101 | "Problem instantiating class '{0}'", bundle.JobDetail.JobType.FullName), ex); 102 | throw sex; 103 | } 104 | } 105 | 106 | public void ReturnJob(IJob job) 107 | { 108 | } 109 | 110 | void SetObjectProperties(T job, JobDataMap jobData) 111 | { 112 | foreach (string key in jobData.Keys) 113 | { 114 | if (_propertyCache.Has(key)) 115 | { 116 | FastProperty property = _propertyCache[key]; 117 | 118 | object value = jobData[key]; 119 | 120 | if (property.Property.PropertyType == typeof(Uri)) 121 | value = new Uri(value.ToString()); 122 | 123 | property.Set(job, value); 124 | } 125 | } 126 | } 127 | 128 | Func CreateConstructor() 129 | { 130 | ConstructorInfo ctor = typeof(T).GetConstructor(new[] {typeof(IServiceBus)}); 131 | if (ctor != null) 132 | return CreateServiceBusConstructor(ctor); 133 | 134 | ctor = typeof(T).GetConstructor(Type.EmptyTypes); 135 | if (ctor != null) 136 | return CreateDefaultConstructor(ctor); 137 | 138 | throw new SchedulerException(string.Format(CultureInfo.InvariantCulture, 139 | "The job class does not have a supported constructor: {0}", typeof(T).ToShortTypeName())); 140 | } 141 | 142 | Func CreateDefaultConstructor(ConstructorInfo constructorInfo) 143 | { 144 | ParameterExpression bus = Expression.Parameter(typeof(IServiceBus), "bus"); 145 | NewExpression @new = Expression.New(constructorInfo); 146 | 147 | return Expression.Lambda>(@new, bus).Compile(); 148 | } 149 | 150 | Func CreateServiceBusConstructor(ConstructorInfo constructorInfo) 151 | { 152 | ParameterExpression bus = Expression.Parameter(typeof(IServiceBus), "bus"); 153 | NewExpression @new = Expression.New(constructorInfo, bus); 154 | 155 | return Expression.Lambda>(@new, bus).Compile(); 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/ScheduleMessageConsumer.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using System; 16 | using System.Collections.Generic; 17 | using System.IO; 18 | using System.Linq; 19 | using System.Text; 20 | using System.Xml.Linq; 21 | using Logging; 22 | using Newtonsoft.Json; 23 | using Newtonsoft.Json.Linq; 24 | using Quartz; 25 | using Scheduling; 26 | 27 | 28 | public class ScheduleMessageConsumer : 29 | Consumes.Context 30 | { 31 | static readonly ILog _log = Logger.Get(); 32 | readonly IScheduler _scheduler; 33 | 34 | public ScheduleMessageConsumer(IScheduler scheduler) 35 | { 36 | _scheduler = scheduler; 37 | } 38 | 39 | public void Consume(IConsumeContext context) 40 | { 41 | if (_log.IsDebugEnabled) 42 | { 43 | _log.DebugFormat("ScheduleMessage: {0} at {1}", context.Message.CorrelationId, 44 | context.Message.ScheduledTime); 45 | } 46 | 47 | string body; 48 | using (var ms = new MemoryStream()) 49 | { 50 | context.BaseContext.CopyBodyTo(ms); 51 | 52 | body = Encoding.UTF8.GetString(ms.ToArray()); 53 | } 54 | 55 | if (string.Compare(context.ContentType, "application/vnd.masstransit+json", 56 | StringComparison.OrdinalIgnoreCase) 57 | == 0) 58 | body = TranslateJsonBody(body, context.Message.Destination.ToString()); 59 | else if (string.Compare(context.ContentType, "application/vnd.masstransit+xml", 60 | StringComparison.OrdinalIgnoreCase) == 0) 61 | body = TranslateXmlBody(body, context.Message.Destination.ToString()); 62 | else 63 | throw new InvalidOperationException("Only JSON and XML messages can be scheduled"); 64 | 65 | IJobDetail jobDetail = JobBuilder.Create() 66 | .RequestRecovery(true) 67 | .WithIdentity(context.Message.CorrelationId.ToString("N")) 68 | .UsingJobData("Destination", ToString(context.Message.Destination)) 69 | .UsingJobData("ResponseAddress", ToString(context.ResponseAddress)) 70 | .UsingJobData("FaultAddress", ToString(context.FaultAddress)) 71 | .UsingJobData("Body", body) 72 | .UsingJobData("ContentType", context.ContentType) 73 | .UsingJobData("MessageId", context.MessageId) 74 | .UsingJobData("RequestId", context.RequestId) 75 | .UsingJobData("ConversationId", context.ConversationId) 76 | .UsingJobData("CorrelationId", context.CorrelationId) 77 | .UsingJobData("HeadersAsJson", JsonConvert.SerializeObject(context.Headers)) 78 | .UsingJobData("ExpirationTime", 79 | context.ExpirationTime.HasValue ? context.ExpirationTime.Value.ToString() : "") 80 | .UsingJobData("Network", context.Network) 81 | .UsingJobData("RetryCount", context.RetryCount) 82 | .Build(); 83 | 84 | ITrigger trigger = TriggerBuilder.Create() 85 | .ForJob(jobDetail) 86 | .StartAt(context.Message.ScheduledTime) 87 | .WithSchedule(SimpleScheduleBuilder.Create().WithMisfireHandlingInstructionFireNow()) 88 | .WithIdentity(new TriggerKey(context.Message.CorrelationId.ToString("N"))) 89 | .Build(); 90 | 91 | _scheduler.ScheduleJob(jobDetail, trigger); 92 | } 93 | 94 | static string ToString(Uri uri) 95 | { 96 | if (uri == null) 97 | return ""; 98 | 99 | return uri.ToString(); 100 | } 101 | 102 | 103 | static string TranslateJsonBody(string body, string destination) 104 | { 105 | JObject envelope = JObject.Parse(body); 106 | 107 | envelope["destinationAddress"] = destination; 108 | 109 | JToken message = envelope["message"]; 110 | 111 | JToken payload = message["payload"]; 112 | JToken payloadType = message["payloadType"]; 113 | 114 | envelope["message"] = payload; 115 | envelope["messageType"] = payloadType; 116 | 117 | return JsonConvert.SerializeObject(envelope, Formatting.Indented); 118 | } 119 | 120 | static string TranslateXmlBody(string body, string destination) 121 | { 122 | using (var reader = new StringReader(body)) 123 | { 124 | XDocument document = XDocument.Load(reader); 125 | 126 | XElement envelope = (from e in document.Descendants("envelope") select e).Single(); 127 | 128 | XElement destinationAddress = (from a in envelope.Descendants("destinationAddress") select a).Single(); 129 | 130 | XElement message = (from m in envelope.Descendants("message") select m).Single(); 131 | IEnumerable messageType = (from mt in envelope.Descendants("messageType") select mt); 132 | 133 | XElement payload = (from p in message.Descendants("payload") select p).Single(); 134 | IEnumerable payloadType = (from pt in message.Descendants("payloadType") select pt); 135 | 136 | message.Remove(); 137 | messageType.Remove(); 138 | 139 | destinationAddress.Value = destination; 140 | 141 | message = new XElement("message"); 142 | message.Add(payload.Descendants()); 143 | envelope.Add(message); 144 | 145 | envelope.Add(payloadType.Select(x => new XElement("messageType", x.Value))); 146 | 147 | return document.ToString(); 148 | } 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/ScheduleMessageJobBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using Quartz; 16 | using Scheduling; 17 | 18 | 19 | public interface ScheduleMessageJobBuilder 20 | { 21 | void Consume(IScheduler scheduler, IConsumeContext context); 22 | } 23 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/ScheduleMessageJobBuilderImpl.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using System; 16 | using Quartz; 17 | using Scheduling; 18 | 19 | 20 | public class ScheduleMessageJobBuilderImpl : 21 | ScheduleMessageJobBuilder 22 | where T : class 23 | { 24 | public void Consume(IScheduler scheduler, IConsumeContext context) 25 | { 26 | IConsumeContext> consumeContext; 27 | if (context.TryGetContext(out consumeContext)) 28 | { 29 | 30 | } 31 | 32 | throw new InvalidOperationException("The message context could not be mapped: {0}" + typeof(T)); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/ScheduleTimeoutConsumer.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using System; 16 | using Logging; 17 | using Quartz; 18 | using Services.Timeout.Messages; 19 | 20 | 21 | public class ScheduleTimeoutConsumer : 22 | Consumes.Context 23 | { 24 | static readonly ILog _log = Logger.Get(); 25 | readonly IScheduler _scheduler; 26 | 27 | public ScheduleTimeoutConsumer(IScheduler scheduler) 28 | { 29 | _scheduler = scheduler; 30 | } 31 | 32 | public void Consume(IConsumeContext context) 33 | { 34 | DateTime startTimeUtc = context.Message.TimeoutAt; 35 | if (startTimeUtc.Kind == DateTimeKind.Local) 36 | startTimeUtc = startTimeUtc.ToUniversalTime(); 37 | 38 | if (_log.IsDebugEnabled) 39 | { 40 | _log.DebugFormat("ScheduleTimeout: {0}[{1} at {2}", context.Message.CorrelationId, 41 | context.Message.Tag, 42 | startTimeUtc); 43 | } 44 | 45 | string triggerKey = context.Message.CorrelationId.ToString("N") + context.Message.Tag; 46 | 47 | var key = new TriggerKey(triggerKey); 48 | 49 | IJobDetail jobDetail = JobBuilder.Create() 50 | .RequestRecovery(true) 51 | .WithIdentity(context.Message.CorrelationId.ToString("N")) 52 | .UsingJobData("Tag", context.Message.Tag) 53 | .UsingJobData("CorrelationId", context.Message.CorrelationId.ToString()) 54 | .Build(); 55 | 56 | 57 | ITrigger trigger = TriggerBuilder.Create() 58 | .ForJob(jobDetail) 59 | .StartAt(startTimeUtc) 60 | .WithIdentity(key) 61 | .Build(); 62 | 63 | if (_scheduler.CheckExists(key)) 64 | { 65 | _scheduler.RescheduleJob(key, trigger); 66 | 67 | context.Bus.Publish(new TimeoutRescheduled 68 | { 69 | CorrelationId = context.Message.CorrelationId, 70 | TimeoutAt = startTimeUtc, 71 | Tag = context.Message.Tag, 72 | }); 73 | } 74 | else 75 | { 76 | _scheduler.ScheduleJob(jobDetail, trigger); 77 | 78 | context.Bus.Publish(new TimeoutScheduled 79 | { 80 | CorrelationId = context.Message.CorrelationId, 81 | TimeoutAt = startTimeUtc, 82 | Tag = context.Message.Tag, 83 | }); 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/ScheduledMessageContext.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using System; 16 | using System.Collections.Generic; 17 | using System.IO; 18 | using Context; 19 | using Serialization.Custom; 20 | 21 | 22 | public class ScheduledMessageContext : 23 | MessageContext, 24 | ISendContext 25 | { 26 | readonly string _body; 27 | 28 | public ScheduledMessageContext(string body) 29 | { 30 | _body = body; 31 | Id = NewId.NextGuid(); 32 | DeclaringMessageType = typeof(ScheduledMessageContext); 33 | } 34 | 35 | public void SetWaitForAck(bool wait = true) 36 | { 37 | } 38 | 39 | public void SetDeliveryMode(DeliveryMode deliveryMode) 40 | { 41 | DeliveryMode = deliveryMode; 42 | } 43 | 44 | public void SerializeTo(Stream stream) 45 | { 46 | using (var nonClosingStream = new NonClosingStream(stream)) 47 | using (var writer = new StreamWriter(nonClosingStream)) 48 | { 49 | writer.Write(_body); 50 | } 51 | } 52 | 53 | public void SetHeaders(IEnumerable> headers) 54 | { 55 | foreach (var entry in headers) 56 | SetHeader(entry.Key, entry.Value); 57 | } 58 | 59 | public bool TryGetContext(out IBusPublishContext context) 60 | where T : class 61 | { 62 | context = null; 63 | return false; 64 | } 65 | 66 | public void NotifySend(IEndpointAddress address) 67 | { 68 | } 69 | 70 | public Guid Id { get; private set; } 71 | public Type DeclaringMessageType { get; private set; } 72 | public DeliveryMode DeliveryMode { get; private set; } 73 | 74 | public bool WaitForAck 75 | { 76 | get { return true; } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/ScheduledMessageJob.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Globalization; 18 | using Logging; 19 | using Newtonsoft.Json; 20 | using Quartz; 21 | 22 | 23 | public class ScheduledMessageJob : 24 | IJob 25 | { 26 | static readonly ILog _log = Logger.Get(); 27 | 28 | readonly IServiceBus _bus; 29 | 30 | public ScheduledMessageJob(IServiceBus bus) 31 | { 32 | _bus = bus; 33 | } 34 | 35 | public string Destination { get; set; } 36 | 37 | public string ExpirationTime { get; set; } 38 | public string ResponseAddress { get; set; } 39 | public string FaultAddress { get; set; } 40 | public string Body { get; set; } 41 | 42 | public string MessageId { get; set; } 43 | public string MessageType { get; set; } 44 | public string ContentType { get; set; } 45 | public string RequestId { get; set; } 46 | public string ConversationId { get; set; } 47 | public string CorrelationId { get; set; } 48 | public string Network { get; set; } 49 | public int RetryCount { get; set; } 50 | public string HeadersAsJson { get; set; } 51 | 52 | public void Execute(IJobExecutionContext context) 53 | { 54 | try 55 | { 56 | var destinationAddress = new Uri(Destination); 57 | Uri sourceAddress = _bus.Endpoint.Address.Uri; 58 | 59 | IEndpoint endpoint = _bus.GetEndpoint(destinationAddress); 60 | 61 | ISendContext messageContext = CreateMessageContext(sourceAddress, destinationAddress); 62 | 63 | endpoint.OutboundTransport.Send(messageContext); 64 | } 65 | catch (Exception ex) 66 | { 67 | string message = string.Format(CultureInfo.InvariantCulture, 68 | "An exception occurred sending message {0} to {1}", MessageType, Destination); 69 | _log.Error(message, ex); 70 | 71 | throw new JobExecutionException(message, ex); 72 | } 73 | } 74 | 75 | 76 | ISendContext CreateMessageContext(Uri sourceAddress, Uri destinationAddress) 77 | { 78 | var context = new ScheduledMessageContext(Body); 79 | 80 | context.SetDestinationAddress(destinationAddress); 81 | context.SetSourceAddress(sourceAddress); 82 | context.SetResponseAddress(ToUri(ResponseAddress)); 83 | context.SetFaultAddress(ToUri(FaultAddress)); 84 | 85 | SetHeaders(context); 86 | context.SetMessageId(MessageId); 87 | context.SetRequestId(RequestId); 88 | context.SetConversationId(ConversationId); 89 | context.SetCorrelationId(CorrelationId); 90 | 91 | if (!string.IsNullOrEmpty(ExpirationTime)) 92 | context.SetExpirationTime(DateTime.Parse(ExpirationTime)); 93 | 94 | context.SetNetwork(Network); 95 | context.SetRetryCount(RetryCount); 96 | context.SetContentType(ContentType); 97 | 98 | return context; 99 | } 100 | 101 | void SetHeaders(ScheduledMessageContext context) 102 | { 103 | if (string.IsNullOrEmpty(HeadersAsJson)) 104 | return; 105 | 106 | var headers = JsonConvert.DeserializeObject>>(HeadersAsJson); 107 | context.SetHeaders(headers); 108 | } 109 | 110 | static Uri ToUri(string s) 111 | { 112 | if (string.IsNullOrEmpty(s)) 113 | return null; 114 | 115 | return new Uri(s); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/ScheduledTimeoutJob.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzIntegration 14 | { 15 | using System; 16 | using System.Globalization; 17 | using Logging; 18 | using Quartz; 19 | using Services.Timeout.Messages; 20 | 21 | 22 | public class ScheduledTimeoutJob : 23 | IJob 24 | { 25 | static readonly ILog _log = Logger.Get(); 26 | 27 | readonly IServiceBus _bus; 28 | 29 | public ScheduledTimeoutJob(IServiceBus bus) 30 | { 31 | _bus = bus; 32 | } 33 | 34 | 35 | public string CorrelationId { get; set; } 36 | public int Tag { get; set; } 37 | 38 | public void Execute(IJobExecutionContext context) 39 | { 40 | try 41 | { 42 | _bus.Publish(new TimeoutExpired 43 | { 44 | CorrelationId = Guid.Parse(CorrelationId), 45 | Tag = Tag, 46 | }); 47 | } 48 | catch (Exception ex) 49 | { 50 | string message = string.Format(CultureInfo.InvariantCulture, 51 | "An exception occurred publishing scheduled timeout {0}[{1}]", CorrelationId, Tag); 52 | _log.Error(message, ex); 53 | 54 | throw new JobExecutionException(message, ex); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/job_scheduling_data_2_0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | Root level node 12 | 13 | 14 | 15 | 16 | 17 | Commands to be executed before scheduling the jobs and triggers in this file. 18 | 19 | 20 | 21 | 22 | Directives to be followed while scheduling the jobs and triggers in this file. 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Version of the XML Schema instance 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Delete all jobs, if any, in the identified group. "*" can be used to identify all groups. Will also result in deleting all triggers related to the jobs. 47 | 48 | 49 | 50 | 51 | Delete all triggers, if any, in the identified group. "*" can be used to identify all groups. Will also result in deletion of related jobs that are non-durable. 52 | 53 | 54 | 55 | 56 | Delete the identified job if it exists (will also result in deleting all triggers related to it). 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable). 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Whether the existing scheduling data (with same identifiers) will be overwritten. If false, and ignore-duplicates is not false, and jobs or triggers with the same names already exist as those in the file, an error will occur. 84 | 85 | 86 | 87 | 88 | If true (and overwrite-existing-data is false) then any job/triggers encountered in this file that have names that already exist in the scheduler will be ignored, and no error will be produced. 89 | 90 | 91 | 92 | 93 | If true trigger's start time is calculated based on earlier run time instead of fixed value. Trigger's start time must be undefined for this to work. 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Define a JobDetail 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | Define a JobDataMap 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | Define a JobDataMap entry 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | Define a Trigger 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | Common Trigger definitions 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | Define a SimpleTrigger 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | Define a CronTrigger 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | Define a DateIntervalTrigger 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | Cron expression (see JavaDoc for examples) 220 | 221 | Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression! 222 | 223 | Regular expressions are not my strong point but I believe this is complete, 224 | with the caveat that order for expressions like 3-0 is not legal but will pass, 225 | and month and day names must be capitalized. 226 | If you want to examine the correctness look for the [\s] to denote the 227 | seperation of individual regular expressions. This is how I break them up visually 228 | to examine them: 229 | 230 | SECONDS: 231 | ( 232 | ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) 233 | | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) 234 | | ([\?]) 235 | | ([\*]) 236 | ) [\s] 237 | MINUTES: 238 | ( 239 | ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) 240 | | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) 241 | | ([\?]) 242 | | ([\*]) 243 | ) [\s] 244 | HOURS: 245 | ( 246 | ((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?) 247 | | (([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3])) 248 | | ([\?]) 249 | | ([\*]) 250 | ) [\s] 251 | DAY OF MONTH: 252 | ( 253 | ((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?) 254 | | (([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) 255 | | (L(-[0-9])?) 256 | | (L(-[1-2][0-9])?) 257 | | (L(-[3][0-1])?) 258 | | (LW) 259 | | ([1-9]W) 260 | | ([1-3][0-9]W) 261 | | ([\?]) 262 | | ([\*]) 263 | )[\s] 264 | MONTH: 265 | ( 266 | ((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?) 267 | | (([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2])) 268 | | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?) 269 | | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) 270 | | ([\?]) 271 | | ([\*]) 272 | )[\s] 273 | DAY OF WEEK: 274 | ( 275 | (([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?) 276 | | ([1-7]/([1-7])) 277 | | (((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?) 278 | | ((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) 279 | | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?) 280 | | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?) 281 | | ([\?]) 282 | | ([\*]) 283 | ) 284 | YEAR (OPTIONAL): 285 | ( 286 | [\s]? 287 | ([\*])? 288 | | ((19[7-9][0-9])|(20[0-9][0-9]))? 289 | | (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))? 290 | | ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)? 291 | ) 292 | 293 | 294 | 295 | 297 | 298 | 299 | 300 | 301 | 302 | Number of times to repeat the Trigger (-1 for indefinite) 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | Simple Trigger Misfire Instructions 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | Cron Trigger Misfire Instructions 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | Date Interval Trigger Misfire Instructions 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | Interval Units 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzIntegration/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Configuration/ConfigurationProviderExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzService.Configuration 14 | { 15 | using System; 16 | using System.Configuration; 17 | using System.Globalization; 18 | using System.Linq; 19 | using Transports.RabbitMq.Configuration.Configurators; 20 | 21 | 22 | public static class ConfigurationProviderExtensions 23 | { 24 | public static Uri GetServiceBusUriFromSetting(this IConfigurationProvider configurationProvider, 25 | string settingName) 26 | { 27 | string queueName = configurationProvider.GetSetting(settingName); 28 | return configurationProvider.GetServiceBusUri(queueName); 29 | } 30 | 31 | public static Uri GetServiceBusUri(this IConfigurationProvider configuration, string queueName) 32 | { 33 | string scheme = configuration.GetSetting("Scheme", "rabbitmq"); 34 | if (string.Compare("rabbitmq", scheme, StringComparison.OrdinalIgnoreCase) == 0) 35 | { 36 | string host = configuration.GetSetting("RabbitMQHost"); 37 | string vhost = configuration.GetSetting("RabbitMQVirtualHost"); 38 | string queueOptions = configuration.GetSetting("RabbitMQOptions", ""); 39 | 40 | var builder = new UriBuilder("rabbitmq", host); 41 | 42 | string[] paths = vhost.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); 43 | 44 | string path = string.Join("/", paths.Concat(new[]{queueName}).ToArray()); 45 | 46 | builder.Path = string.Format("/{0}", string.Join("/", paths)); 47 | builder.Path = path; 48 | builder.Query = queueOptions; 49 | 50 | return builder.Uri; 51 | } 52 | 53 | if (string.Compare("msmq", scheme, StringComparison.OrdinalIgnoreCase) == 0) 54 | { 55 | string host = configuration.GetSetting("MSMQHost"); 56 | 57 | var builder = new UriBuilder("msmq", host); 58 | 59 | return new Uri(builder.Uri, queueName); 60 | } 61 | 62 | throw new ConfigurationErrorsException(string.Format(CultureInfo.InvariantCulture, 63 | "An unrecognized scheme was found: {0}", scheme)); 64 | } 65 | 66 | 67 | public static void ConfigureRabbitMqHost(this RabbitMqTransportFactoryConfigurator configurator, 68 | IConfigurationProvider configuration) 69 | { 70 | Uri hostAddress = GetServiceBusUri(configuration, "ignored"); 71 | 72 | string userName = configuration.GetSetting("RabbitMQUsername"); 73 | string password = configuration.GetSetting("RabbitMQPassword"); 74 | 75 | configurator.ConfigureHost(hostAddress, h => 76 | { 77 | h.SetUsername(userName); 78 | h.SetPassword(password); 79 | }); 80 | } 81 | 82 | 83 | public static string GetSetting(this IConfigurationProvider configuration, string key, string defaultValue) 84 | { 85 | string value = configuration.GetSetting(key); 86 | if (string.IsNullOrEmpty(value)) 87 | return defaultValue; 88 | 89 | return value; 90 | } 91 | 92 | public static int GetSetting(this IConfigurationProvider configuration, string key, int defaultValue) 93 | { 94 | string value = configuration.GetSetting(key); 95 | if (string.IsNullOrEmpty(value)) 96 | return defaultValue; 97 | 98 | int result; 99 | if (int.TryParse(value, out result)) 100 | return result; 101 | 102 | return defaultValue; 103 | } 104 | 105 | public static bool GetSetting(this IConfigurationProvider configuration, string key, bool defaultValue) 106 | { 107 | string value = configuration.GetSetting(key); 108 | if (string.IsNullOrEmpty(value)) 109 | return defaultValue; 110 | 111 | bool result; 112 | if (bool.TryParse(value, out result)) 113 | return result; 114 | 115 | return defaultValue; 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Configuration/ConnectionStringProvider.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzService.Configuration 2 | { 3 | using System.Text.RegularExpressions; 4 | 5 | 6 | public class ConnectionStringProvider : 7 | IConnectionStringProvider 8 | { 9 | IConfigurationProvider _configurationProvider; 10 | 11 | public ConnectionStringProvider(IConfigurationProvider configurationProvider) 12 | { 13 | _configurationProvider = configurationProvider; 14 | } 15 | 16 | public string GetConnectionString(string connectionName, string serverName = null, string databaseName = null) 17 | { 18 | string connectionString = _configurationProvider.GetConnectionString(connectionName); 19 | if (connectionString == null) 20 | return null; 21 | 22 | if (serverName != null) 23 | connectionString = ReplaceServerName(connectionString, serverName); 24 | 25 | if (databaseName != null) 26 | connectionString = ReplaceDatabaseName(connectionString, databaseName); 27 | 28 | return connectionString; 29 | } 30 | 31 | string ReplaceServerName(string value, string serverName) 32 | { 33 | if (serverName.IndexOfAny(new[] {'.', ':', '\\'}) >= 0) 34 | return Regex.Replace(value, @"\s*Server\s*=\s*(?[^;]+)", "Server=" + serverName, 35 | RegexOptions.IgnoreCase); 36 | return Regex.Replace(value, @"\s*Server\s*=\s*(?[^;\.:]+)", "Server=" + serverName, 37 | RegexOptions.IgnoreCase); 38 | } 39 | 40 | string ReplaceDatabaseName(string value, string databaseName) 41 | { 42 | return Regex.Replace(value, @"\s*Database\s*=\s*(?[^;]+)", "Database=" + databaseName, 43 | RegexOptions.IgnoreCase); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Configuration/FileConfigurationProvider.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzService.Configuration 2 | { 3 | using System; 4 | using System.Configuration; 5 | using System.Reflection; 6 | 7 | 8 | public class FileConfigurationProvider : 9 | IConfigurationProvider 10 | { 11 | readonly Func _appSettings; 12 | readonly Func _connectionStrings; 13 | readonly Func _getSection; 14 | 15 | public FileConfigurationProvider() 16 | : this(Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly()) 17 | { 18 | } 19 | 20 | public FileConfigurationProvider(Assembly assembly) 21 | { 22 | var map = new ExeConfigurationFileMap(); 23 | 24 | map.ExeConfigFilename = assembly.Location + ".config"; 25 | 26 | Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(map, 27 | ConfigurationUserLevel.None); 28 | 29 | _appSettings = () => configuration.AppSettings; 30 | _connectionStrings = () => configuration.ConnectionStrings; 31 | _getSection = configuration.GetSection; 32 | } 33 | 34 | public string GetSetting(string name) 35 | { 36 | AppSettingsSection settings = _appSettings(); 37 | if (settings == null) 38 | return null; 39 | 40 | KeyValueConfigurationElement element = settings.Settings[name]; 41 | if (element == null) 42 | return null; 43 | 44 | return element.Value; 45 | } 46 | 47 | public string GetConnectionString(string name) 48 | { 49 | ConnectionStringsSection connectionStrings = _connectionStrings(); 50 | if (connectionStrings == null) 51 | return null; 52 | 53 | ConnectionStringSettings setting = connectionStrings.ConnectionStrings[name]; 54 | if (setting == null) 55 | return null; 56 | 57 | return setting.ConnectionString; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Configuration/IConfigurationProvider.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzService.Configuration 2 | { 3 | public interface IConfigurationProvider 4 | { 5 | string GetSetting(string name); 6 | string GetConnectionString(string name); 7 | } 8 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Configuration/IConnectionProvider.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzService.Configuration 2 | { 3 | using System.Data; 4 | 5 | 6 | public interface IConnectionProvider 7 | { 8 | IDbConnection GetConnection(); 9 | 10 | /// 11 | /// Get a command object for executing a query against a database 12 | /// 13 | /// The SQL string 14 | /// An owned command object 15 | IDbCommand GetCommand(string sql); 16 | } 17 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Configuration/IConnectionStringProvider.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzService.Configuration 2 | { 3 | /// 4 | /// A connection string source used to build out connection strings 5 | /// 6 | public interface IConnectionStringProvider 7 | { 8 | /// 9 | /// Returns the requested connection string, optionally replacing the server or catalog 10 | /// 11 | /// The name of the connection string 12 | /// Optional, the server name to use instead of the name in the setting source 13 | /// Optional, the catalog name to use instead of the name in the setting source 14 | /// A properly formatted connection string 15 | string GetConnectionString(string connectionName, string serverName = null, string databaseName = null); 16 | 17 | } 18 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Configuration/SqlConnectionProvider.cs: -------------------------------------------------------------------------------- 1 | namespace MassTransit.QuartzService.Configuration 2 | { 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | 6 | 7 | public class SqlConnectionProvider : 8 | IConnectionProvider 9 | { 10 | string _connectionString; 11 | 12 | public SqlConnectionProvider(IConnectionStringProvider connectionStringProvider, string connectionName) 13 | { 14 | _connectionString = connectionStringProvider.GetConnectionString(connectionName); 15 | } 16 | 17 | public IDbConnection GetConnection() 18 | { 19 | return new SqlConnection(_connectionString); 20 | } 21 | 22 | public IDbCommand GetCommand(string sql) 23 | { 24 | var connection = new SqlConnection(_connectionString); 25 | connection.Open(); 26 | 27 | var command = new SqlCommand(sql, connection); 28 | 29 | return command; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/MassTransit.QuartzService.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {989BA511-C126-4C88-A74B-BAD83DF2291B} 9 | Exe 10 | Properties 11 | MassTransit.QuartzService 12 | MassTransit.QuartzService 13 | v4.0 14 | 15 | 16 | 512 17 | ..\ 18 | true 19 | 20 | 21 | x86 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 30 | 31 | x86 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | 39 | 40 | true 41 | bin\Debug\ 42 | DEBUG;TRACE 43 | full 44 | AnyCPU 45 | bin\Debug\MassTransit.QuartzService.exe.CodeAnalysisLog.xml 46 | true 47 | GlobalSuppressions.cs 48 | prompt 49 | MinimumRecommendedRules.ruleset 50 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 51 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 52 | true 53 | 54 | 55 | bin\Release\ 56 | TRACE 57 | true 58 | pdbonly 59 | AnyCPU 60 | bin\Release\MassTransit.QuartzService.exe.CodeAnalysisLog.xml 61 | true 62 | GlobalSuppressions.cs 63 | prompt 64 | MinimumRecommendedRules.ruleset 65 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 66 | false 67 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 68 | 69 | 70 | 71 | ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll 72 | 73 | 74 | ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll 75 | 76 | 77 | False 78 | ..\packages\Common.Logging.Log4Net1211.3.0.0\lib\net40\Common.Logging.Log4Net1211.dll 79 | 80 | 81 | False 82 | ..\packages\log4net.2.0.3\lib\net40-full\log4net.dll 83 | 84 | 85 | ..\packages\Magnum.2.1.3\lib\NET40\Magnum.dll 86 | True 87 | 88 | 89 | ..\packages\MassTransit.2.10.2\lib\net40\MassTransit.dll 90 | True 91 | 92 | 93 | ..\packages\MassTransit.Log4Net.2.10.2\lib\net40\MassTransit.Log4NetIntegration.dll 94 | True 95 | 96 | 97 | ..\packages\MassTransit.MSMQ.2.10.2\lib\net40\MassTransit.Transports.MSMQ.dll 98 | True 99 | 100 | 101 | ..\packages\MassTransit.RabbitMQ.2.10.2\lib\net40\MassTransit.Transports.RabbitMq.dll 102 | True 103 | 104 | 105 | ..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll 106 | True 107 | 108 | 109 | ..\packages\Quartz.2.3.2\lib\net40\Quartz.dll 110 | 111 | 112 | ..\packages\RabbitMQ.Client.3.4.3\lib\net35\RabbitMQ.Client.dll 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | ..\packages\Topshelf.3.2.0\lib\net40-full\Topshelf.dll 121 | True 122 | 123 | 124 | ..\packages\Topshelf.Log4Net.3.2.0\lib\net40-full\Topshelf.Log4Net.dll 125 | 126 | 127 | 128 | 129 | SolutionVersion.cs 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | Designer 145 | 146 | 147 | PreserveNewest 148 | Designer 149 | 150 | 151 | 152 | 153 | 154 | {2F7DB49B-B650-4B57-BB9D-5D1B913CCACC} 155 | MassTransit.QuartzIntegration 156 | 157 | 158 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00} 159 | MassTransit.Scheduling 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 174 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzService 14 | { 15 | using System; 16 | using System.Diagnostics; 17 | using Configuration; 18 | using Log4NetIntegration.Logging; 19 | using Monitoring; 20 | using Topshelf; 21 | using Topshelf.Logging; 22 | using Topshelf.Runtime; 23 | 24 | 25 | class Program 26 | { 27 | static int Main() 28 | { 29 | Log4NetLogWriterFactory.Use("log4net.config"); 30 | Log4NetLogger.Use(); 31 | 32 | 33 | return (int)HostFactory.Run(x => 34 | { 35 | x.AfterInstall(() => 36 | { 37 | VerifyEventLogSourceExists(); 38 | 39 | // this will force the performance counters to register during service installation 40 | // making them created - of course using the InstallUtil stuff completely skips 41 | // this part of the install :( 42 | ServiceBusPerformanceCounters counters = ServiceBusPerformanceCounters.Instance; 43 | 44 | string name = counters.ConsumerThreadCount.Name; 45 | Console.WriteLine("Consumer Thread Count Counter Installed: {0}", name); 46 | }); 47 | 48 | x.Service(CreateService); 49 | }); 50 | } 51 | 52 | static void VerifyEventLogSourceExists() 53 | { 54 | if (!EventLog.SourceExists("MassTransit")) 55 | EventLog.CreateEventSource("MassTransit Quartz Service", "MassTransit"); 56 | } 57 | 58 | static ScheduleMessageService CreateService(HostSettings arg) 59 | { 60 | var configurationProvider = new FileConfigurationProvider(); 61 | 62 | return new ScheduleMessageService(configurationProvider); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/ScheduleMessageService.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.QuartzService 14 | { 15 | using System; 16 | using System.Linq; 17 | using Configuration; 18 | using Logging; 19 | using Quartz; 20 | using Quartz.Impl; 21 | using QuartzIntegration; 22 | using Topshelf; 23 | 24 | 25 | public class ScheduleMessageService : 26 | ServiceControl 27 | { 28 | readonly IConfigurationProvider _configurationProvider; 29 | readonly int _consumerLimit; 30 | readonly Uri _controlQueueUri; 31 | readonly ILog _log = Logger.Get(); 32 | readonly IScheduler _scheduler; 33 | IServiceBus _bus; 34 | 35 | public ScheduleMessageService(IConfigurationProvider configurationProvider) 36 | { 37 | _configurationProvider = configurationProvider; 38 | _controlQueueUri = configurationProvider.GetServiceBusUriFromSetting("ControlQueueName"); 39 | _consumerLimit = configurationProvider.GetSetting("ConsumerLimit", Math.Min(2, Environment.ProcessorCount)); 40 | 41 | _scheduler = CreateScheduler(); 42 | } 43 | 44 | public bool Start(HostControl hostControl) 45 | { 46 | try 47 | { 48 | _bus = ServiceBusFactory.New(x => 49 | { 50 | // just support everything by default 51 | x.UseMsmq(); 52 | x.UseRabbitMq(rmq => rmq.ConfigureRabbitMqHost(_configurationProvider)); 53 | x.UseJsonSerializer(); 54 | 55 | // move this to app.config 56 | x.ReceiveFrom(_controlQueueUri); 57 | x.SetConcurrentConsumerLimit(_consumerLimit); 58 | 59 | x.Subscribe(s => 60 | { 61 | s.Consumer(() => new ScheduleMessageConsumer(_scheduler)); 62 | s.Consumer(() => new CancelScheduledMessageConsumer(_scheduler)); 63 | 64 | s.Consumer(() => new ScheduleTimeoutConsumer(_scheduler)); 65 | s.Consumer(() => new CancelScheduledTimeoutConsumer(_scheduler)); 66 | }); 67 | }); 68 | 69 | if (_log.IsInfoEnabled) 70 | _log.Info(GetProbeInfo()); 71 | 72 | _scheduler.JobFactory = new MassTransitJobFactory(_bus); 73 | 74 | _scheduler.Start(); 75 | } 76 | catch (Exception) 77 | { 78 | _scheduler.Shutdown(); 79 | throw; 80 | } 81 | 82 | return true; 83 | } 84 | 85 | string GetProbeInfo() 86 | { 87 | var strings = _bus.Probe().Entries 88 | .Where(x => !x.Key.StartsWith("zz.")) 89 | .Select(x => string.Format("{0}: {1}", x.Key, x.Value)); 90 | 91 | var probe = string.Join(Environment.NewLine, strings.ToArray()); 92 | return probe; 93 | } 94 | 95 | public bool Stop(HostControl hostControl) 96 | { 97 | _scheduler.Standby(); 98 | 99 | if (_bus != null) 100 | _bus.Dispose(); 101 | 102 | _scheduler.Shutdown(); 103 | 104 | return true; 105 | } 106 | 107 | static IScheduler CreateScheduler() 108 | { 109 | ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); 110 | 111 | IScheduler scheduler = schedulerFactory.GetScheduler(); 112 | 113 | return scheduler; 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/job_scheduling_data_2_0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | Root level node 12 | 13 | 14 | 15 | 16 | 17 | Commands to be executed before scheduling the jobs and triggers in this file. 18 | 19 | 20 | 21 | 22 | Directives to be followed while scheduling the jobs and triggers in this file. 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Version of the XML Schema instance 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Delete all jobs, if any, in the identified group. "*" can be used to identify all groups. Will also result in deleting all triggers related to the jobs. 47 | 48 | 49 | 50 | 51 | Delete all triggers, if any, in the identified group. "*" can be used to identify all groups. Will also result in deletion of related jobs that are non-durable. 52 | 53 | 54 | 55 | 56 | Delete the identified job if it exists (will also result in deleting all triggers related to it). 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable). 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Whether the existing scheduling data (with same identifiers) will be overwritten. If false, and ignore-duplicates is not false, and jobs or triggers with the same names already exist as those in the file, an error will occur. 84 | 85 | 86 | 87 | 88 | If true (and overwrite-existing-data is false) then any job/triggers encountered in this file that have names that already exist in the scheduler will be ignored, and no error will be produced. 89 | 90 | 91 | 92 | 93 | If true trigger's start time is calculated based on earlier run time instead of fixed value. Trigger's start time must be undefined for this to work. 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Define a JobDetail 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | Define a JobDataMap 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | Define a JobDataMap entry 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | Define a Trigger 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | Common Trigger definitions 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | Define a SimpleTrigger 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | Define a CronTrigger 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | Define a DateIntervalTrigger 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | Cron expression (see JavaDoc for examples) 220 | 221 | Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression! 222 | 223 | Regular expressions are not my strong point but I believe this is complete, 224 | with the caveat that order for expressions like 3-0 is not legal but will pass, 225 | and month and day names must be capitalized. 226 | If you want to examine the correctness look for the [\s] to denote the 227 | seperation of individual regular expressions. This is how I break them up visually 228 | to examine them: 229 | 230 | SECONDS: 231 | ( 232 | ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) 233 | | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) 234 | | ([\?]) 235 | | ([\*]) 236 | ) [\s] 237 | MINUTES: 238 | ( 239 | ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) 240 | | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) 241 | | ([\?]) 242 | | ([\*]) 243 | ) [\s] 244 | HOURS: 245 | ( 246 | ((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?) 247 | | (([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3])) 248 | | ([\?]) 249 | | ([\*]) 250 | ) [\s] 251 | DAY OF MONTH: 252 | ( 253 | ((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?) 254 | | (([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) 255 | | (L(-[0-9])?) 256 | | (L(-[1-2][0-9])?) 257 | | (L(-[3][0-1])?) 258 | | (LW) 259 | | ([1-9]W) 260 | | ([1-3][0-9]W) 261 | | ([\?]) 262 | | ([\*]) 263 | )[\s] 264 | MONTH: 265 | ( 266 | ((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?) 267 | | (([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2])) 268 | | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?) 269 | | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) 270 | | ([\?]) 271 | | ([\*]) 272 | )[\s] 273 | DAY OF WEEK: 274 | ( 275 | (([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?) 276 | | ([1-7]/([1-7])) 277 | | (((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?) 278 | | ((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) 279 | | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?) 280 | | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?) 281 | | ([\?]) 282 | | ([\*]) 283 | ) 284 | YEAR (OPTIONAL): 285 | ( 286 | [\s]? 287 | ([\*])? 288 | | ((19[7-9][0-9])|(20[0-9][0-9]))? 289 | | (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))? 290 | | ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)? 291 | ) 292 | 293 | 294 | 295 | 297 | 298 | 299 | 300 | 301 | 302 | Number of times to repeat the Trigger (-1 for indefinite) 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | Simple Trigger Misfire Instructions 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | Cron Trigger Misfire Instructions 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | Date Interval Trigger Misfire Instructions 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | Interval Units 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/log4net.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/MassTransit.QuartzService/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/MassTransit.Scheduling/CancelScheduledMessage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.Scheduling 14 | { 15 | using System; 16 | 17 | 18 | public interface CancelScheduledMessage : 19 | CorrelatedBy 20 | { 21 | /// 22 | /// The date/time this message was created 23 | /// 24 | DateTime Timestamp { get; } 25 | 26 | /// 27 | /// The token of the scheduled message 28 | /// 29 | Guid TokenId { get; } 30 | } 31 | } -------------------------------------------------------------------------------- /src/MassTransit.Scheduling/MassTransit.Scheduling.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {863EBFC8-DFA6-45E7-B9ED-4D180FE2BE00} 9 | Library 10 | Properties 11 | MassTransit.Scheduling 12 | MassTransit.Scheduling 13 | v4.0 14 | 512 15 | ..\ 16 | true 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\Magnum.2.1.3\lib\NET40\Magnum.dll 39 | True 40 | 41 | 42 | ..\packages\MassTransit.2.10.2\lib\net40\MassTransit.dll 43 | True 44 | 45 | 46 | ..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll 47 | True 48 | 49 | 50 | 51 | 52 | 53 | 54 | SolutionVersion.cs 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /src/MassTransit.Scheduling/ScheduleMessage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.Scheduling 14 | { 15 | using System; 16 | using System.Collections.Generic; 17 | 18 | 19 | public interface ScheduleMessage : 20 | CorrelatedBy 21 | { 22 | /// 23 | /// The time at which the message should be published 24 | /// 25 | DateTime ScheduledTime { get; } 26 | 27 | /// 28 | /// The message types implemented by the message 29 | /// 30 | IList PayloadType { get; } 31 | 32 | /// 33 | /// The destination where the message should be sent 34 | /// 35 | Uri Destination { get; } 36 | } 37 | 38 | 39 | public interface ScheduleMessage : 40 | ScheduleMessage 41 | where T : class 42 | { 43 | /// 44 | /// The message to be published 45 | /// 46 | T Payload { get; } 47 | } 48 | } -------------------------------------------------------------------------------- /src/MassTransit.Scheduling/ScheduleMessageExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.Scheduling 14 | { 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Linq; 18 | 19 | 20 | /// 21 | /// Extensions for scheduling publish/send message 22 | /// 23 | public static class ScheduleMessageExtensions 24 | { 25 | /// 26 | /// Sends a ScheduleMessage command to the endpoint, using the specified arguments 27 | /// 28 | /// The scheduled message type 29 | /// The endpoint of the message scheduling service 30 | /// The destination address where the schedule message should be sent 31 | /// The time when the message should be sent to the endpoint 32 | /// The message to send 33 | /// A handled to the scheduled message 34 | public static ScheduledMessage ScheduleSend(this IEndpoint endpoint, Uri destinationAddress, DateTime scheduledTime, T message) 35 | where T : class 36 | { 37 | var command = new ScheduleMessageCommand(scheduledTime, destinationAddress, message); 38 | 39 | endpoint.Send>(command); 40 | 41 | return new ScheduledMessageHandle(command.CorrelationId, command.ScheduledTime, command.Destination, 42 | command.Payload); 43 | } 44 | 45 | /// 46 | /// Sends a ScheduleMessage command to the endpoint, using the specified arguments 47 | /// 48 | /// The scheduled message type 49 | /// The endpoint of the message scheduling service 50 | /// The destionation address for the schedule message 51 | /// The time when the message should be sent to the endpoint 52 | /// The message to send 53 | /// 54 | public static ScheduledMessage ScheduleSend(this IEndpoint endpoint, IEndpointAddress destinationAddress, DateTime scheduledTime, T message) 55 | where T : class 56 | { 57 | return ScheduleSend(endpoint, destinationAddress.Uri, scheduledTime, message); 58 | } 59 | 60 | /// 61 | /// Sends a ScheduleMessage command to the endpoint, using the specified arguments 62 | /// 63 | /// The scheduled message type 64 | /// The endpoint of the message scheduling service 65 | /// The bus instance where the scheduled message should be sent 66 | /// The time when the message should be sent to the endpoint 67 | /// The message to send 68 | /// 69 | public static ScheduledMessage ScheduleSend(this IEndpoint endpoint, IServiceBus bus, DateTime scheduledTime, T message) 70 | where T : class 71 | { 72 | return ScheduleSend(endpoint, bus.Endpoint.Address.Uri, scheduledTime, message); 73 | } 74 | 75 | /// 76 | /// Sends a ScheduleMessage command to the endpoint, using the specified arguments 77 | /// 78 | /// The scheduled message type 79 | /// The endpoint of the message scheduling service 80 | /// The destination endpoint where the scheduled message should be sent 81 | /// The time when the message should be sent to the endpoint 82 | /// The message to send 83 | /// 84 | public static ScheduledMessage ScheduleSend(this IEndpoint endpoint, IEndpoint destinationEndpoint, DateTime scheduledTime, T message) 85 | where T : class 86 | { 87 | return ScheduleSend(endpoint, destinationEndpoint.Address.Uri, scheduledTime, message); 88 | } 89 | 90 | /// 91 | /// Cancel a scheduled message using the scheduled message instance 92 | /// 93 | /// The endpoint of the scheduling service 94 | /// The schedule message reference 95 | public static void CancelScheduledSend(this IEndpoint endpoint, ScheduledMessage message) 96 | where T : class 97 | { 98 | if (message == null) 99 | throw new ArgumentNullException("message"); 100 | 101 | CancelScheduledSend(endpoint, message.TokenId); 102 | } 103 | 104 | /// 105 | /// Cancel a scheduled message using the tokenId that was returned when the message was scheduled. 106 | /// 107 | /// The endpoint of the scheduling service 108 | /// The tokenId of the scheduled message 109 | public static void CancelScheduledSend(this IEndpoint endpoint, Guid tokenId) 110 | { 111 | var command = new CancelScheduledMessageCommand(tokenId); 112 | 113 | endpoint.Send(command); 114 | } 115 | 116 | 117 | /// 118 | /// Schedules a message to be sent to the bus using a Publish, which should only be used when 119 | /// the quartz service is on a single shared queue or behind a distributor 120 | /// 121 | /// The scheduled message type 122 | /// The bus from which the scheduled message command should be published 123 | /// The destination address where the schedule message should be sent 124 | /// The time when the message should be sent to the endpoint 125 | /// The message to send 126 | /// Optional: A callback that gives the caller access to the publish context. 127 | /// A handled to the scheduled message 128 | public static ScheduledMessage ScheduleMessage(this IServiceBus bus, Uri destinationAddress, DateTime scheduledTime, T message, Action>> contextCallback = null) 129 | where T : class 130 | { 131 | var command = new ScheduleMessageCommand(scheduledTime, destinationAddress, message); 132 | 133 | bus.Publish>(command, contextCallback ?? (c => {})); 134 | 135 | return new ScheduledMessageHandle(command.CorrelationId, command.ScheduledTime, command.Destination, 136 | command.Payload); 137 | } 138 | 139 | /// 140 | /// Schedules a message to be sent to the bus using a Publish, which should only be used when 141 | /// the quartz service is on a single shared queue or behind a distributor 142 | /// 143 | /// The scheduled message type 144 | /// The bus from which the scheduled message command should be published 145 | /// The destination address where the schedule message should be sent 146 | /// The time when the message should be sent to the endpoint 147 | /// The message to send 148 | /// A handled to the scheduled message 149 | public static ScheduledMessage ScheduleMessage(this IServiceBus bus, IEndpointAddress destinationAddress, DateTime scheduledTime, T message) 150 | where T : class 151 | { 152 | return ScheduleMessage(bus, destinationAddress.Uri, scheduledTime, message); 153 | } 154 | 155 | /// 156 | /// Schedules a message to be sent to the bus using a Publish, which should only be used when 157 | /// the quartz service is on a single shared queue or behind a distributor 158 | /// 159 | /// The scheduled message type 160 | /// The bus from which the scheduled message command should be published 161 | /// The destination address where the schedule message should be sent 162 | /// The time when the message should be sent to the endpoint 163 | /// The message to send 164 | /// A handled to the scheduled message 165 | public static ScheduledMessage ScheduleMessage(this IServiceBus bus, IEndpoint destinationEndpoint, DateTime scheduledTime, T message) 166 | where T : class 167 | { 168 | return ScheduleMessage(bus, destinationEndpoint.Address.Uri, scheduledTime, message); 169 | } 170 | 171 | /// 172 | /// Schedules a message to be sent to the bus using a Publish, which should only be used when 173 | /// the quartz service is on a single shared queue or behind a distributor 174 | /// 175 | /// The scheduled message type 176 | /// The bus from which the scheduled message command should be published 177 | /// The time when the message should be sent to the endpoint 178 | /// The message to send 179 | /// /// Optional: A callback that gives the caller access to the publish context. 180 | /// A handled to the scheduled message 181 | public static ScheduledMessage ScheduleMessage(this IServiceBus bus, DateTime scheduledTime, T message, Action>> contextCallback = null) 182 | where T : class 183 | { 184 | return ScheduleMessage(bus, bus.Endpoint.Address.Uri, scheduledTime, message, contextCallback); 185 | } 186 | 187 | /// 188 | /// Cancel a scheduled message using the scheduled message instance 189 | /// 190 | /// 191 | /// 192 | public static void CancelScheduledMessage(this IServiceBus bus, ScheduledMessage message) 193 | where T : class 194 | { 195 | if (message == null) 196 | throw new ArgumentNullException("message"); 197 | 198 | CancelScheduledMessage(bus, message.TokenId); 199 | } 200 | 201 | /// 202 | /// Cancel a scheduled message using the tokenId that was returned when the message was scheduled. 203 | /// 204 | /// 205 | /// The tokenId of the scheduled message 206 | public static void CancelScheduledMessage(this IServiceBus bus, Guid tokenId) 207 | { 208 | var command = new CancelScheduledMessageCommand(tokenId); 209 | 210 | bus.Publish(command); 211 | } 212 | 213 | 214 | class CancelScheduledMessageCommand : 215 | CancelScheduledMessage 216 | { 217 | public CancelScheduledMessageCommand(Guid tokenId) 218 | { 219 | CorrelationId = NewId.NextGuid(); 220 | Timestamp = DateTime.UtcNow; 221 | 222 | TokenId = tokenId; 223 | } 224 | 225 | public Guid TokenId { get; private set; } 226 | public DateTime Timestamp { get; private set; } 227 | public Guid CorrelationId { get; private set; } 228 | } 229 | 230 | 231 | class ScheduleMessageCommand : 232 | ScheduleMessage 233 | where T : class 234 | { 235 | public ScheduleMessageCommand(DateTime scheduledTime, Uri destination, T payload) 236 | { 237 | CorrelationId = NewId.NextGuid(); 238 | 239 | ScheduledTime = scheduledTime.Kind == DateTimeKind.Local 240 | ? scheduledTime.ToUniversalTime() 241 | : scheduledTime; 242 | 243 | Destination = destination; 244 | Payload = payload; 245 | 246 | PayloadType = typeof(T).GetMessageTypes() 247 | .Select(x => new MessageUrn(x).ToString()) 248 | .ToList(); 249 | } 250 | 251 | public Guid CorrelationId { get; private set; } 252 | public DateTime ScheduledTime { get; private set; } 253 | public IList PayloadType { get; private set; } 254 | public Uri Destination { get; private set; } 255 | public T Payload { get; private set; } 256 | } 257 | 258 | 259 | class ScheduledMessageHandle : 260 | ScheduledMessage 261 | where T : class 262 | { 263 | public ScheduledMessageHandle(Guid tokenId, DateTime scheduledTime, Uri destination, T payload) 264 | { 265 | TokenId = tokenId; 266 | ScheduledTime = scheduledTime; 267 | Destination = destination; 268 | Payload = payload; 269 | } 270 | 271 | public Guid TokenId { get; private set; } 272 | public DateTime ScheduledTime { get; private set; } 273 | public Uri Destination { get; private set; } 274 | public T Payload { get; private set; } 275 | } 276 | } 277 | } -------------------------------------------------------------------------------- /src/MassTransit.Scheduling/ScheduledMessage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007-2012 Chris Patterson, Dru Sellers, Travis Smith, et. al. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | // this file except in compliance with the License. You may obtain a copy of the 5 | // License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software distributed 10 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | // specific language governing permissions and limitations under the License. 13 | namespace MassTransit.Scheduling 14 | { 15 | using System; 16 | 17 | 18 | public interface ScheduledMessage 19 | where T : class 20 | { 21 | Guid TokenId { get; } 22 | DateTime ScheduledTime { get; } 23 | Uri Destination { get; } 24 | T Payload { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/MassTransit.Scheduling/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | --------------------------------------------------------------------------------