pomelo-citrus-scheduler 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +20 -0
- data/Rakefile +0 -0
- data/citrus-scheduler.gemspec +27 -0
- data/lib/citrus-scheduler.rb +8 -0
- data/lib/citrus-scheduler/cron_trigger.rb +19 -0
- data/lib/citrus-scheduler/cron_trigger_decoder.rb +14 -0
- data/lib/citrus-scheduler/job.rb +66 -0
- data/lib/citrus-scheduler/schedule.rb +114 -0
- data/lib/citrus-scheduler/simple_trigger.rb +38 -0
- data/lib/citrus-scheduler/version.rb +7 -0
- data/test/test_schedule.rb +28 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 602975c89705979ad0a6b2477c38134e4c0ed8f2
|
4
|
+
data.tar.gz: 481027405914536c19e7300e5d93b2824a75397b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e6929058f53f2b85b78370423e02668b718e23bc13606f141165ac2c02f56072c8abc77fae589562c76f3f89618eb33a4d1be9d3a6241d0de7c2411c035f2e9
|
7
|
+
data.tar.gz: e1c5c5ab749fa8a56a5218fb147027f52619231c6288444e0ec4a4f84ca40853e9c8cc58072f38918bf5fdbcf072fa94e140e45bfe1a92912eadbb96c0d44270
|
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
## Welcome to pomelo-citrus-scheduler
|
2
|
+
|
3
|
+
pomelo-citrus-scheduler is a simple clone of pomelo-scheduler written in Ruby using EventMachine.
|
4
|
+
|
5
|
+
## Motivation
|
6
|
+
|
7
|
+
Since NodeJS is influenced by Ruby EventMachine and Python's Twisted model, Ruby should also be able to have its own game server framework like pomelo.
|
8
|
+
|
9
|
+
Ruby is a very expressive and eloquent programming language. I was an RoR programmer before and I really like Ruby, When developing this project, I have used many skills like meta-programming and they give me the real pleasures.
|
10
|
+
|
11
|
+
Recently, I would focus on my daily work, so I open source this project and hope to have more people participate in this project.
|
12
|
+
|
13
|
+
## Todo
|
14
|
+
|
15
|
+
This gem is the very first gem I have done in my whole work, it needs to be improved but it already has the ablity to provide the basic infrastructure to other gems, other gems exist in my own repository.
|
16
|
+
|
17
|
+
## Links
|
18
|
+
|
19
|
+
* [EventMachine](https://github.com/eventmachine/eventmachine)
|
20
|
+
* [pomelo-scheduler](https://github.com/NetEase/pomelo-scheduler)
|
data/Rakefile
ADDED
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 15 July 2014
|
4
|
+
|
5
|
+
$:.push File.expand_path('../lib', __FILE__)
|
6
|
+
|
7
|
+
require 'citrus-scheduler/version'
|
8
|
+
|
9
|
+
Gem::Specification.new do |spec|
|
10
|
+
spec.name = 'pomelo-citrus-scheduler'
|
11
|
+
spec.version = CitrusScheduler::VERSION
|
12
|
+
spec.platform = Gem::Platform::RUBY
|
13
|
+
spec.authors = ['MinixLi']
|
14
|
+
spec.email = 'MinixLi1986@gmail.com'
|
15
|
+
spec.description = %q{pomelo-citrus-scheduler is a simple clone of pomelo-scheduler, it is a schedule tool and provide a schedule module which is highly efficient and can support large number job schedule}
|
16
|
+
spec.summary = %q{pomelo-scheduler clone written in Ruby using EventMachine}
|
17
|
+
spec.homepage = 'https://github.com/minixli/pomelo-citrus-scheduler'
|
18
|
+
spec.license = 'MIT'
|
19
|
+
|
20
|
+
spec.files = `git ls-files`.split($/)
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_dependency('algorithms', '~> 0')
|
26
|
+
spec.add_dependency('eventmachine', '~> 0')
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 15 July 2014
|
4
|
+
|
5
|
+
require 'citrus-scheduler/cron_trigger_decoder'
|
6
|
+
|
7
|
+
module CitrusScheduler
|
8
|
+
# CronTrigger
|
9
|
+
#
|
10
|
+
#
|
11
|
+
class CronTrigger
|
12
|
+
# Create a new cron trigger
|
13
|
+
#
|
14
|
+
# @param [String] args
|
15
|
+
# @param [Object] job
|
16
|
+
def initialize args='', job
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 15 July 2014
|
4
|
+
|
5
|
+
module CitrusScheduler
|
6
|
+
# CronTrigger
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class CronTriggerDecoder
|
10
|
+
# Create a new cron trigger decoder
|
11
|
+
def initialize
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 15 July 2014
|
4
|
+
|
5
|
+
require 'citrus-scheduler/cron_trigger'
|
6
|
+
require 'citrus-scheduler/simple_trigger'
|
7
|
+
|
8
|
+
module CitrusScheduler
|
9
|
+
# Job
|
10
|
+
#
|
11
|
+
#
|
12
|
+
class Job
|
13
|
+
@job_id = 1
|
14
|
+
@job_count = 0
|
15
|
+
|
16
|
+
class << self
|
17
|
+
attr_accessor :job_id, :job_count
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :job_id, :run_time
|
21
|
+
|
22
|
+
# Create a new job
|
23
|
+
#
|
24
|
+
# @param [#call] job_cb
|
25
|
+
# @param [Hash] job_cb_args
|
26
|
+
# @param [Hash, String] trigger_args
|
27
|
+
def initialize job_cb, job_cb_args={}, trigger_args={}
|
28
|
+
@job_cb = job_cb
|
29
|
+
@job_cb_args = job_cb_args
|
30
|
+
|
31
|
+
if trigger_args.instance_of? Hash
|
32
|
+
@type = :simple_job
|
33
|
+
@trigger = SimpleTrigger.new trigger_args, self
|
34
|
+
elsif trigger_args.instance_of? String
|
35
|
+
@type = :cron_job
|
36
|
+
@trigger = CronTrigger.new trigger_args, self
|
37
|
+
else
|
38
|
+
end
|
39
|
+
|
40
|
+
@job_id = Job.job_id
|
41
|
+
Job.job_id += 1
|
42
|
+
|
43
|
+
@run_time = 0
|
44
|
+
end
|
45
|
+
|
46
|
+
# Run the job
|
47
|
+
def run
|
48
|
+
begin
|
49
|
+
Job.job_count += 1
|
50
|
+
@run_time += 1
|
51
|
+
@job_cb.call @job_cb_args
|
52
|
+
rescue => err
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get the current execution time
|
57
|
+
def execute_time
|
58
|
+
@trigger.execute_time
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get the next execution time
|
62
|
+
def next_execute_time
|
63
|
+
@trigger.next_execute_time
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 15 July 2014
|
4
|
+
|
5
|
+
require 'algorithms'
|
6
|
+
require 'citrus-scheduler/job'
|
7
|
+
|
8
|
+
module CitrusScheduler
|
9
|
+
@jobs_map = {}
|
10
|
+
@jobs_queue = Containers::PriorityQueue.new
|
11
|
+
@timer = nil
|
12
|
+
@accuracy = 0.01
|
13
|
+
|
14
|
+
# Schedule a new job
|
15
|
+
#
|
16
|
+
# @param [#call] job_cb
|
17
|
+
# @param [Hash] job_cb_args
|
18
|
+
# @param [Hash] trigger_args
|
19
|
+
def self.schedule_job job_cb, job_cb_args={}, trigger_args={}
|
20
|
+
job = Job.new job_cb, job_cb_args, trigger_args
|
21
|
+
job_id = job.job_id
|
22
|
+
execute_time = job.execute_time
|
23
|
+
|
24
|
+
@jobs_map[job_id] = job
|
25
|
+
element = {
|
26
|
+
:job_id => job_id,
|
27
|
+
:execute_time => execute_time
|
28
|
+
}
|
29
|
+
|
30
|
+
cur_job = @jobs_queue.next
|
31
|
+
unless cur_job && execute_time >= cur_job[:execute_time]
|
32
|
+
@jobs_queue.push element, -execute_time
|
33
|
+
set_timer job
|
34
|
+
return job_id
|
35
|
+
end
|
36
|
+
|
37
|
+
@jobs_queue.push element, -execute_time
|
38
|
+
return job_id
|
39
|
+
end
|
40
|
+
|
41
|
+
# Cancel a job
|
42
|
+
#
|
43
|
+
# @param [Integer] job_id
|
44
|
+
def self.cancel_job job_id
|
45
|
+
cur_job = @jobs_queue.next
|
46
|
+
if cur_job && job_id == cur_job[:job_id]
|
47
|
+
@jobs_queue.pop
|
48
|
+
@jobs_map.delete job_id
|
49
|
+
@timer.cancel
|
50
|
+
execute_job
|
51
|
+
end
|
52
|
+
@jobs_map.delete job_id
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
# Clear last timeout and schedule the next job, it will automatically
|
57
|
+
# run the job that need to run now
|
58
|
+
#
|
59
|
+
# @param [Object] job
|
60
|
+
def self.set_timer job
|
61
|
+
@timer.cancel if @timer
|
62
|
+
@timer = EM::Timer.new(job.execute_time - Time.now.to_f) {
|
63
|
+
execute_job
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
# Execute job
|
68
|
+
def self.execute_job
|
69
|
+
job = peek_next_job
|
70
|
+
|
71
|
+
while job && (job.execute_time - Time.now.to_f) < @accuracy
|
72
|
+
job.run
|
73
|
+
@jobs_queue.pop
|
74
|
+
|
75
|
+
next_time = job.next_execute_time
|
76
|
+
|
77
|
+
if next_time
|
78
|
+
element = {
|
79
|
+
:job_id => job.job_id,
|
80
|
+
:execute_time => next_time
|
81
|
+
}
|
82
|
+
@jobs_queue.push element, -next_time
|
83
|
+
else
|
84
|
+
@jobs_map.delete job.job_id
|
85
|
+
end
|
86
|
+
job = peek_next_job
|
87
|
+
end
|
88
|
+
|
89
|
+
return unless job
|
90
|
+
set_timer job
|
91
|
+
end
|
92
|
+
|
93
|
+
# Peek next job
|
94
|
+
def self.peek_next_job
|
95
|
+
return nil if @jobs_queue.size <= 0
|
96
|
+
|
97
|
+
job = nil
|
98
|
+
loop do
|
99
|
+
job = @jobs_map[@jobs_queue.next[:job_id]]
|
100
|
+
@jobs_queue.pop unless job
|
101
|
+
break if job || @jobs_queue.size <= 0
|
102
|
+
end
|
103
|
+
job
|
104
|
+
end
|
105
|
+
|
106
|
+
# Get next job
|
107
|
+
def self.get_next_job
|
108
|
+
job = nil
|
109
|
+
while !job && @jobs_queue.size > 0
|
110
|
+
job = @jobs_map[@jobs_queue.pop[:job_id]]
|
111
|
+
end
|
112
|
+
job
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 15 July 2014
|
4
|
+
|
5
|
+
module CitrusScheduler
|
6
|
+
# SimpleTrigger
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class SimpleTrigger
|
10
|
+
# Create a new simple trigger
|
11
|
+
#
|
12
|
+
# @param [Hash] args Options
|
13
|
+
#
|
14
|
+
# @option args [Integer] start_time
|
15
|
+
# @option args [Integer] interval
|
16
|
+
# @option args [Integer] count
|
17
|
+
# @option args [Object] job
|
18
|
+
def initialize args={}, job
|
19
|
+
@next_time = args[:start_time] || Time.now.to_f
|
20
|
+
@interval = args[:interval] || -1
|
21
|
+
@count = args[:count] || -1
|
22
|
+
@job = job
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get the current execution time
|
26
|
+
def execute_time
|
27
|
+
@next_time
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get the next execution time
|
31
|
+
def next_execute_time
|
32
|
+
if (@count > 0 && @count <= @job.run_time) || @interval <= 0
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
@next_time += @interval
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 16 July 2014
|
4
|
+
|
5
|
+
require File.expand_path('../../lib/citrus-scheduler', __FILE__)
|
6
|
+
|
7
|
+
def simple_job_cb args={}
|
8
|
+
puts "simple job #{args[:id]} with interval: #{args[:interval]} executed at #{Time.now}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_simple_job_schedule count
|
12
|
+
count.times do |count|
|
13
|
+
start_time = Time.now.to_f + rand * 10
|
14
|
+
interval = rand * 60 + 0.1
|
15
|
+
args = [
|
16
|
+
method(:simple_job_cb),
|
17
|
+
{ :id => count, :interval => interval },
|
18
|
+
{ :start_time => start_time, :interval => interval }
|
19
|
+
]
|
20
|
+
CitrusScheduler.schedule_job *args
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test
|
25
|
+
test_simple_job_schedule 5
|
26
|
+
end
|
27
|
+
|
28
|
+
EM.run { test }
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pomelo-citrus-scheduler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- MinixLi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: algorithms
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: eventmachine
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: pomelo-citrus-scheduler is a simple clone of pomelo-scheduler, it is
|
42
|
+
a schedule tool and provide a schedule module which is highly efficient and can
|
43
|
+
support large number job schedule
|
44
|
+
email: MinixLi1986@gmail.com
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- citrus-scheduler.gemspec
|
52
|
+
- lib/citrus-scheduler.rb
|
53
|
+
- lib/citrus-scheduler/cron_trigger.rb
|
54
|
+
- lib/citrus-scheduler/cron_trigger_decoder.rb
|
55
|
+
- lib/citrus-scheduler/job.rb
|
56
|
+
- lib/citrus-scheduler/schedule.rb
|
57
|
+
- lib/citrus-scheduler/simple_trigger.rb
|
58
|
+
- lib/citrus-scheduler/version.rb
|
59
|
+
- test/test_schedule.rb
|
60
|
+
homepage: https://github.com/minixli/pomelo-citrus-scheduler
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.2.2
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: pomelo-scheduler clone written in Ruby using EventMachine
|
84
|
+
test_files:
|
85
|
+
- test/test_schedule.rb
|