evenitron 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +65 -0
- data/lib/evenitron/collector_client.rb +76 -0
- data/lib/evenitron/delayed_job.rb +112 -0
- data/lib/evenitron/evenitron.rb +32 -0
- data/lib/evenitron/logger.rb +11 -0
- data/lib/evenitron/resque.rb +149 -0
- data/lib/evenitron.rb +12 -0
- metadata +64 -0
data/README.markdown
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Setting up with delayed_job
|
2
|
+
|
3
|
+
There are two options for setting up Evenitron to monitor your delayed_job tasks.
|
4
|
+
|
5
|
+
Firstly, add the gem to your Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'evenitron-ruby', :git => 'git@github.com:evenitron/evenitron-ruby.git'
|
9
|
+
```
|
10
|
+
|
11
|
+
*We'll use the git references if possible until things are public.*
|
12
|
+
|
13
|
+
Then you need to configure it within your `boot.rb` for Rails (I have no idea if this is the right file but it works). You can either do this explicitly:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require 'evenitron/delayed_job'
|
17
|
+
|
18
|
+
Evenitron::DelayedJob.configure do
|
19
|
+
system_key 'benchmarking'
|
20
|
+
# collector_url 'http://localhost:5000/'
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
Or you can rely on the environment variables `EVENITRON_SYSTEM_KEY` and `EVENITRON_COLLECTOR_URL`:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'evenitron/delayed_job'
|
28
|
+
|
29
|
+
Evenitron::DelayedJob.configure
|
30
|
+
```
|
31
|
+
|
32
|
+
You must specify your system key either through configuration or the `EVENITRON_SYSTEM_KEY` environment variable but you will normally rely on the default collector URL of `https://collector.evenitron.com/`.
|
33
|
+
|
34
|
+
# Setting up with resque
|
35
|
+
|
36
|
+
There are two options for setting up Evenitron to monitor your delayed_job tasks.
|
37
|
+
|
38
|
+
Firstly, add the gem to your Gemfile:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
gem 'evenitron-ruby', :git => 'git@github.com:evenitron/evenitron-ruby.git'
|
42
|
+
```
|
43
|
+
|
44
|
+
*We'll use the git references if possible until things are public.*
|
45
|
+
|
46
|
+
Then you need to configure it within your `boot.rb` for Rails (I have no idea if this is the right file but it works). You can either do this explicitly:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
require 'evenitron/resque'
|
50
|
+
|
51
|
+
Evenitron::Resque.configure do
|
52
|
+
system_key 'benchmarking'
|
53
|
+
# collector_url 'http://localhost:5000/'
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
Or you can rely on the environment variables `EVENITRON_SYSTEM_KEY` and `EVENITRON_COLLECTOR_URL`:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
require 'evenitron/resque'
|
61
|
+
|
62
|
+
Evenitron::Resque.configure
|
63
|
+
```
|
64
|
+
|
65
|
+
You must specify your system key either through configuration or the `EVENITRON_SYSTEM_KEY` environment variable but you will normally rely on the default collector URL of `https://collector.evenitron.com/`.
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Evenitron
|
2
|
+
|
3
|
+
class CollectorClient
|
4
|
+
|
5
|
+
include Evenitron::Logger
|
6
|
+
|
7
|
+
DEFAULT_URL = "https://collector.evenitron.com/"
|
8
|
+
|
9
|
+
def initialize(system_key, url = DEFAULT_URL, component = nil)
|
10
|
+
@system_key = system_key
|
11
|
+
@url = url
|
12
|
+
@user_agent = 'evenitron-ruby 0.1'
|
13
|
+
@user_agent = "#{@user_agent} (#{component})" if component
|
14
|
+
@simulate_requests = ENV['EVENITRON_SIMULATE_REQUESTS'] == 'true'
|
15
|
+
log.warn 'Simulating Evenitron messages' if @simulate_requests
|
16
|
+
end
|
17
|
+
|
18
|
+
def job_queued(args)
|
19
|
+
send_message :queued, args
|
20
|
+
end
|
21
|
+
|
22
|
+
def job_started(args)
|
23
|
+
send_message :started, args
|
24
|
+
end
|
25
|
+
|
26
|
+
def job_failed(args)
|
27
|
+
send_message :failed, args
|
28
|
+
end
|
29
|
+
|
30
|
+
def job_complete(args)
|
31
|
+
send_message :complete, args
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def send_message(stage, args)
|
37
|
+
send message(stage, args)
|
38
|
+
end
|
39
|
+
|
40
|
+
def send(msg)
|
41
|
+
json = msg.to_json
|
42
|
+
|
43
|
+
if @simulate_requests
|
44
|
+
log.info "Simulating message for #{@system_key} to #{@url} - #{json}"
|
45
|
+
return nil
|
46
|
+
else
|
47
|
+
log.debug "Sending message for #{@system_key} to #{@url} - #{json}"
|
48
|
+
end
|
49
|
+
|
50
|
+
Thread.new do
|
51
|
+
begin
|
52
|
+
RestClient.post @url, json, :content_type => nil, 'Evenitron-Key' => @system_key, 'User-Agent' => @user_agent
|
53
|
+
rescue => e
|
54
|
+
log.error "Failed to send message for #{@system_key} to #{@url} - #{json}"
|
55
|
+
log.debug e
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def message(stage, args)
|
63
|
+
msg = args.dup
|
64
|
+
msg[:stage] = stage
|
65
|
+
msg[:version] = 1
|
66
|
+
msg[:timestamp] = since_epoch(Time.now)
|
67
|
+
msg
|
68
|
+
end
|
69
|
+
|
70
|
+
def since_epoch(time)
|
71
|
+
(time.to_f * 1000).to_i
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative '../evenitron'
|
2
|
+
require 'delayed_job'
|
3
|
+
|
4
|
+
module Evenitron
|
5
|
+
|
6
|
+
module DelayedJob
|
7
|
+
|
8
|
+
def self.configure(&block)
|
9
|
+
dj = Evenitron::DelayedJobCollector.new
|
10
|
+
dj.configure &block unless block.nil?
|
11
|
+
dj.start!
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class DelayedJobCollector
|
18
|
+
|
19
|
+
include Evenitron::Logger
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@collector_url = ENV['EVENITRON_COLLECTOR_URL']
|
23
|
+
@system_key = ENV['EVENITRON_SYSTEM_KEY']
|
24
|
+
end
|
25
|
+
|
26
|
+
def configure(&block)
|
27
|
+
instance_eval &block
|
28
|
+
end
|
29
|
+
|
30
|
+
def system_key(key)
|
31
|
+
@system_key = key
|
32
|
+
end
|
33
|
+
|
34
|
+
def api_key(key)
|
35
|
+
@api_key = key
|
36
|
+
end
|
37
|
+
|
38
|
+
def collector_url(url)
|
39
|
+
@collector_url = url
|
40
|
+
end
|
41
|
+
|
42
|
+
def start!
|
43
|
+
log.info "Registering delayed_job evenitron collector with system key #{@system_key} to send messages to #{@collector_url}"
|
44
|
+
@client = Evenitron::CollectorClient.new @system_key, @collector_url, 'dj'
|
45
|
+
register_lifecycle_hooks
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def lifecycle
|
51
|
+
Delayed::Worker.lifecycle
|
52
|
+
end
|
53
|
+
|
54
|
+
def register_lifecycle_hooks
|
55
|
+
log.info "Registering delayed_job job queued callback"
|
56
|
+
lifecycle.around :enqueue do |job, &block|
|
57
|
+
result = block.call(job)
|
58
|
+
job_queued job
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
log.info "Registering delayed_job job failed callback"
|
63
|
+
lifecycle.before :failure do |worker, job|
|
64
|
+
job_failed job
|
65
|
+
end
|
66
|
+
|
67
|
+
log.info "Registering delayed_job job requeued callback"
|
68
|
+
lifecycle.after :error do |worker, job|
|
69
|
+
job_queued job unless job.failed? or job.frozen?
|
70
|
+
end
|
71
|
+
|
72
|
+
log.info "Registering delayed_job job started callback"
|
73
|
+
log.info "Registering delayed_job job complete callback"
|
74
|
+
lifecycle.around :perform do |worker, job, &block|
|
75
|
+
job_started job, worker
|
76
|
+
result = block.call(worker, job)
|
77
|
+
job_complete job if result
|
78
|
+
result
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def job_queued(job)
|
83
|
+
id = get_id(job)
|
84
|
+
log.info "Sending job queued message for job #{job.id} (evenitron id #{id})"
|
85
|
+
@client.job_queued :id => id, :queue => job.class.table_name, :task => job.name
|
86
|
+
end
|
87
|
+
|
88
|
+
def job_started(job, worker)
|
89
|
+
id = get_id(job)
|
90
|
+
log.info "Sending job started message for job #{job.id} (evenitron id #{id})"
|
91
|
+
@client.job_started :id => id, :worker => worker.name, :task => job.name
|
92
|
+
end
|
93
|
+
|
94
|
+
def job_failed(job)
|
95
|
+
id = get_id(job)
|
96
|
+
log.info "Sending job failed message for job #{job.id} (evenitron id #{id})"
|
97
|
+
@client.job_failed :id => id, :task => job.name
|
98
|
+
end
|
99
|
+
|
100
|
+
def job_complete(job)
|
101
|
+
id = get_id(job)
|
102
|
+
log.info "Sending job complete message for job #{job.id} (evenitron id #{id})"
|
103
|
+
@client.job_complete :id => id, :task => job.name
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_id(job)
|
107
|
+
Evenitron.encode job.class.table_name, job.id
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Evenitron
|
2
|
+
|
3
|
+
def self.logger
|
4
|
+
@@logger ||= default_logger
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.logger=(logger)
|
8
|
+
@@logger = logger
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.encode(*values)
|
12
|
+
value = values.join ':'
|
13
|
+
cleanse_base64 Base64.encode64(value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.generate_id(length = 64)
|
17
|
+
cleanse_base64 SecureRandom.base64(length)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def self.default_logger
|
23
|
+
logger = ::Logger.new(STDOUT)
|
24
|
+
logger.level = ::Logger::INFO
|
25
|
+
logger
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.cleanse_base64(value)
|
29
|
+
value.gsub /[\s=]/, ''
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require_relative '../evenitron'
|
2
|
+
require 'resque'
|
3
|
+
|
4
|
+
module Evenitron
|
5
|
+
|
6
|
+
class NullResqueCollector
|
7
|
+
|
8
|
+
include Evenitron::Logger
|
9
|
+
|
10
|
+
def job_queued(queue, item)
|
11
|
+
log.warn "EVENITRON NOT CONFIGURED : Not sending job queued message for job #{item['evenitron_id']}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def job_started(job)
|
15
|
+
log.info "EVENITRON NOT CONFIGURED : Not sending job started message for job #{job.evenitron_id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def job_failed(job)
|
19
|
+
log.info "EVENITRON NOT CONFIGURED : Not sending job failed message for job #{job.evenitron_id}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def job_complete(job)
|
23
|
+
log.info "EVENITRON NOT CONFIGURED : Not sending job complete message for job #{job.evenitron_id}"
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
module Resque
|
29
|
+
|
30
|
+
@@collector = Evenitron::NullResqueCollector.new
|
31
|
+
|
32
|
+
def self.configure(&block)
|
33
|
+
rc = Evenitron::ResqueCollector.new
|
34
|
+
rc.configure &block unless block.nil?
|
35
|
+
rc.start!
|
36
|
+
@@collector = rc
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.collector
|
41
|
+
@@collector
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class ResqueCollector
|
47
|
+
|
48
|
+
include Evenitron::Logger
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
@collector_url = ENV['EVENITRON_COLLECTOR_URL']
|
52
|
+
@system_key = ENV['EVENITRON_SYSTEM_KEY']
|
53
|
+
end
|
54
|
+
|
55
|
+
def configure(&block)
|
56
|
+
instance_eval &block
|
57
|
+
end
|
58
|
+
|
59
|
+
def system_key(key)
|
60
|
+
@system_key = key
|
61
|
+
end
|
62
|
+
|
63
|
+
def api_key(key)
|
64
|
+
@api_key = key
|
65
|
+
end
|
66
|
+
|
67
|
+
def collector_url(url)
|
68
|
+
@collector_url = url
|
69
|
+
end
|
70
|
+
|
71
|
+
def start!
|
72
|
+
log.info "Registering resque evenitron collector with system key #{@system_key} to send messages to #{@collector_url}"
|
73
|
+
@client = Evenitron::CollectorClient.new @system_key, @collector_url, 'resque'
|
74
|
+
end
|
75
|
+
|
76
|
+
def job_queued(queue, item)
|
77
|
+
id = get_id(item)
|
78
|
+
log.info "Sending job queued message for job #{id}"
|
79
|
+
@client.job_queued :id => id, :queue => queue, :task => item[:class]
|
80
|
+
end
|
81
|
+
|
82
|
+
def job_started(job)
|
83
|
+
log.info "Sending job started message for job #{job.evenitron_id}"
|
84
|
+
@client.job_started :id => job.evenitron_id, :worker => job.worker.to_s, :task => job.payload['class']
|
85
|
+
end
|
86
|
+
|
87
|
+
def job_failed(job)
|
88
|
+
log.info "Sending job failed message for job #{job.evenitron_id}"
|
89
|
+
@client.job_failed :id => job.evenitron_id, :task => job.payload['class']
|
90
|
+
end
|
91
|
+
|
92
|
+
def job_complete(job)
|
93
|
+
log.info "Sending job complete message for job #{job.evenitron_id}"
|
94
|
+
@client.job_complete :id => job.evenitron_id, :task => job.payload['class']
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def get_id(item)
|
100
|
+
item['evenitron_id']
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
module Resque
|
108
|
+
|
109
|
+
class << self
|
110
|
+
|
111
|
+
alias :base_push :push
|
112
|
+
|
113
|
+
def push(queue, item)
|
114
|
+
item['evenitron_id'] ||= Evenitron.generate_id
|
115
|
+
base_push(queue, item)
|
116
|
+
Evenitron::Resque.collector.job_queued queue, item
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
class Job
|
122
|
+
|
123
|
+
alias :base_perform :perform
|
124
|
+
|
125
|
+
def perform
|
126
|
+
begin
|
127
|
+
Evenitron.logger.debug "Processing job #{evenitron_id}"
|
128
|
+
Evenitron::Resque.collector.job_started self
|
129
|
+
|
130
|
+
result = base_perform
|
131
|
+
Evenitron::Resque.collector.job_complete self
|
132
|
+
|
133
|
+
Evenitron.logger.debug "Processed job #{evenitron_id}, result was #{result}"
|
134
|
+
result
|
135
|
+
rescue => e
|
136
|
+
Evenitron.logger.fatal "Exception occurred whilst processing job #{evenitron_id}"
|
137
|
+
Evenitron.logger.debug e.inspect
|
138
|
+
Evenitron::Resque.collector.job_failed self
|
139
|
+
raise e
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def evenitron_id
|
144
|
+
@payload['evenitron_id']
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
data/lib/evenitron.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'base64'
|
3
|
+
require 'rest_client'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'logger'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
module Evenitron ; end
|
9
|
+
|
10
|
+
require_relative 'evenitron/evenitron'
|
11
|
+
require_relative 'evenitron/logger'
|
12
|
+
require_relative 'evenitron/collector_client'
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evenitron
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Evenitron
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-25 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest-client
|
16
|
+
requirement: &70228307216040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.7
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70228307216040
|
25
|
+
description: Ruby client for Evenitron with hooks for delayed_job and resque
|
26
|
+
email:
|
27
|
+
- support@evenitron.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- lib/evenitron/collector_client.rb
|
33
|
+
- lib/evenitron/delayed_job.rb
|
34
|
+
- lib/evenitron/evenitron.rb
|
35
|
+
- lib/evenitron/logger.rb
|
36
|
+
- lib/evenitron/resque.rb
|
37
|
+
- lib/evenitron.rb
|
38
|
+
- README.markdown
|
39
|
+
homepage: https://github.com/evenitron/evenitron-ruby
|
40
|
+
licenses: []
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
requirements: []
|
58
|
+
rubyforge_project: evenitron-ruby
|
59
|
+
rubygems_version: 1.8.15
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: Ruby client for Evenitron
|
63
|
+
test_files: []
|
64
|
+
has_rdoc:
|