ruby-clock 0.6.0 → 0.8.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0fec8d8c66e1783260e73fad69f39572677871d722d1c62437c94741452340e
4
- data.tar.gz: 03e5b84ef4cd5277da5623173ca70887dc3aac0296445e573459050341376b78
3
+ metadata.gz: 7e8d972bb2c2468f53d943f233e4e799df71a449b6f7b8c00a1ddbea33c54c92
4
+ data.tar.gz: fc97259d0575bd220f79dd25206128001eece56ec51eda06d95f28d718b65080
5
5
  SHA512:
6
- metadata.gz: 70134452766d69a5dbebc795cc31babb56ac14b6363aa6416379600fb6fa0546ccc9b131a17342b1376a101acc89ae746a1f9f19795274224a72e9291f9f6eba
7
- data.tar.gz: 4aeb5e68d8108f40e10c11b4ea9fe4a3ad390ba4652afcc4e71cbc11c8c49b36be3f4c8b762f17eda1cffc488f1d5b803388bfb5f3e219962c289dd581549f81
6
+ metadata.gz: 6dcf79cbebb137a9f04e920b8d6ff0f910bd61536e3e666297217aef8d9942c656fca0d67d794c753ab42a9e035be364bcf3d3b6e465058ebfe7e8683fa94fea
7
+ data.tar.gz: a3ca20e788af53d77d5526aaacb3b7ff4b07e8852e7586fe181e1681985b32b5bce3a9f0a305507be335dfeee7399567a6cd31afe8262b6e0b84db9cd2d9a75a
data/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ ## 0.8.0 RC3
2
+
3
+ * make terrapin and posix-spawn gems optional
4
+
5
+ ## 0.8.0 RC2
6
+
7
+ * fix detection of Rails constant, for non-rails apps
8
+
9
+ ## 0.8.0 RC1
10
+
11
+ * automatically wrap jobs with rails reloader
12
+ * ability to run rake tasks
13
+ * ability to run shell commands
14
+ * nicer shutdown logging, indicating when shutdown process begins and ends
15
+ * fix approach for error fallbacks when when calculating job identifier (probably never encountered)
16
+
17
+ ## 0.7.0
18
+
19
+ * ability to specify the name of the file with job definitions, e.g. `bundle exec clock clocks/MyClockfile`
20
+ * ability to specify the amount of time ruby-clock will wait before forcing threads to shut down
21
+
22
+ ## 0.6.0
23
+
24
+ * job identifiers
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-clock (0.6.0)
4
+ ruby-clock (0.8.0.rc2)
5
5
  method_source
6
6
  rufus-scheduler (~> 3.8)
7
7
 
@@ -9,9 +9,9 @@ GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
11
  concurrent-ruby (1.1.9)
12
- et-orbi (1.2.4)
12
+ et-orbi (1.2.5)
13
13
  tzinfo
14
- fugit (1.5.0)
14
+ fugit (1.5.2)
15
15
  et-orbi (~> 1.1, >= 1.1.8)
16
16
  raabro (~> 1.4)
17
17
  method_source (1.0.0)
@@ -30,4 +30,4 @@ DEPENDENCIES
30
30
  ruby-clock!
31
31
 
32
32
  BUNDLED WITH
33
- 2.1.4
33
+ 2.2.23
data/README.md CHANGED
@@ -16,6 +16,7 @@ The clock process will respond to signals INT (^c at the command line) and
16
16
  TERM (signal sent by environments such as Heroku and other PaaS's when shutting down).
17
17
  In both cases, the clock will stop running jobs and give existing jobs 29 seconds
18
18
  to stop before killing them.
19
+ You can change this number with `RUBY_CLOCK_SHUTDOWN_WAIT_SECONDS` in the environment.
19
20
 
20
21
  ## Installation
21
22
 
@@ -55,6 +56,11 @@ To start your clock process:
55
56
 
56
57
  bundle exec clock
57
58
 
59
+ To use a file other than Clockfile for job definitions, specify it.
60
+ This will ignore Clockfile and only read jobs from clocks/MyClockfile:
61
+
62
+ bundle exec clock clocks/MyClockfile
63
+
58
64
  ### Rails
59
65
 
60
66
  Install the `clock` binstub and commit to your repo.
@@ -65,6 +71,12 @@ To run your clock process in your app's environment:
65
71
 
66
72
  bundle exec rails runner bin/clock
67
73
 
74
+ To get smarter database connection management (such as in the case of a database restart or upgrade,
75
+ and maybe other benefits) and code reloading in dev (app code, not the code in Clockfile itself),
76
+ jobs are automatically wrapped in the
77
+ [rails app reloader](https://guides.rubyonrails.org/threading_and_code_execution.html).
78
+
79
+
68
80
  ### Non-Rails
69
81
 
70
82
  Require your app's code at the top of Clockfile:
@@ -83,6 +95,28 @@ Add this line to your Procfile
83
95
  clock: bundle exec rails runner bin/clock
84
96
  ```
85
97
 
98
+ You might have a main clock for general scheduled jobs, and then standalone ones
99
+ if your system has something where you want to monitor and adjust resources
100
+ for that work more precisely. Here, maybe the main clock needs a 2GB instance,
101
+ and the others each need 1GB all to themselves:
102
+
103
+ ```
104
+ clock: bundle exec rails runner bin/clock
105
+ thing_checker: bundle exec rails runner bin/clock clocks/thing_checker.rb
106
+ thing_reporter: bundle exec rails runner bin/clock clocks/thing_reporter.rb
107
+ ```
108
+
109
+ Because of this feature, do I regret using "Clockfile" instead of, say, "clock.rb"? Maybe.
110
+
111
+ #### Observing logs
112
+
113
+ Because STDOUT does not flush until a certain amount of data has gone into it,
114
+ you might not immediately see the ruby-clock startup message or job output if
115
+ viewing logs in a deployed environment such as Heroku where the logs are redirected
116
+ to another process or file. To change this behavior and have logs flush immediately,
117
+ add `$stdout.sync = true` to the top of your Clockfile.
118
+
119
+
86
120
  ## More Config and Capabilities
87
121
 
88
122
  ### Error Handling
@@ -102,6 +136,49 @@ You can define before, after, and around callbacks which will run for all jobs.
102
136
  Read [the rufus-scheduler documentation](https://github.com/jmettraux/rufus-scheduler/#callbacks)
103
137
  to learn how to do this. Where the documentation references `s`, you should use `schedule`.
104
138
 
139
+ ### Shell commands
140
+
141
+ You can run shell commands in your jobs.
142
+
143
+ ```ruby
144
+ schedule.every '1 day' do
145
+ shell('sh scripts/process_stuff.sh')
146
+ end
147
+ ```
148
+
149
+ By default they will be run with
150
+ [ruby backticks](https://livebook.manning.com/concept/ruby/backtick).
151
+ For better performance, install the [terrapin](https://github.com/thoughtbot/terrapin)
152
+ and [posix-spawn](https://github.com/rtomayko/posix-spawn) gems.
153
+
154
+ `shell` is a convenience method which just passes the string on.
155
+ If you want to use other terrapin features, you can skip the `shell` command
156
+ and use terrapin directly:
157
+
158
+ ```ruby
159
+ schedule.every '1 day' do
160
+ line = Terrapin::CommandLine.new('optimize_png', ":file")
161
+ Organization.with_new_logos.find_each do |o|
162
+ line.run(file: o.logo_file_path)
163
+ o.update!(logo_optimized: true)
164
+ end
165
+ end
166
+ ```
167
+
168
+ ### Rake tasks
169
+
170
+ You can run tasks from within the persistent runtime of ruby-clock, without
171
+ needing to shell out and start another process.
172
+
173
+ ```ruby
174
+ schedule.every '1 day' do
175
+ rake('reports:daily')
176
+ end
177
+ ```
178
+
179
+ There is also `rake_execute` and `rake_async`. See [the code](https://github.com/jjb/ruby-clock/blob/main/lib/ruby-clock.rb)
180
+ and [this article](https://code.jjb.cc/running-rake-tasks-from-within-ruby-on-rails-code) for more info.
181
+
105
182
  ### Job Identifier
106
183
 
107
184
  ruby-clock adds the `identifier` method to `Rufus::Scheduler::Job`. This method will return the job's
@@ -113,12 +190,12 @@ fallback is the line number of the job in Clockfile.
113
190
  Some examples of jobs and their identifiers:
114
191
 
115
192
  ```ruby
116
- schedule.every '1 second', name: 'my job' do |variable|
193
+ schedule.every '1 second', name: 'my job' do
117
194
  Foo.bar
118
195
  end
119
196
  # => my job
120
197
 
121
- schedule.every '1 day', name: 'my job' do |variable|
198
+ schedule.every '1 day' do
122
199
  daily_things = Foo.setup_daily
123
200
  daily_things.process
124
201
  # TODO: figure out best time of day
@@ -126,7 +203,7 @@ end
126
203
  # => daily_things.process
127
204
 
128
205
  # n.b. ruby-clock isn't yet smart enough to remove trailing comments
129
- schedule.every '1 week', name: 'my job' do |variable|
206
+ schedule.every '1 week' do
130
207
  weekly_things = Foo.setup_weekly
131
208
  weekly_things.process # does this work???!1~
132
209
  end
@@ -168,6 +245,14 @@ so anything you can do on this instance, you can do in your Clockfile.
168
245
  Perhaps in the future ruby-clock will add some easier specific configuration
169
246
  capabilities for some things. Let me know if you have a request!
170
247
 
248
+ ## Syntax highlighting for Clockfile
249
+
250
+ To tell github and maybe other systems to syntax highlight Clockfile, put this in a .gitattributes file:
251
+
252
+ ```gitattributes
253
+ Clockfile linguist-language=Ruby
254
+ ```
255
+
171
256
 
172
257
  ## License
173
258
 
@@ -0,0 +1 @@
1
+ Clockfile linguist-language=Ruby
@@ -0,0 +1,11 @@
1
+ def schedule.on_error(job, error)
2
+ raise error
3
+ end
4
+
5
+ schedule.every('2 seconds') do
6
+ puts "hello from a ruby-clock job"
7
+ end
8
+
9
+ schedule.every('2 seconds') do
10
+ shell 'say hello'
11
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem 'ruby-clock', path: '../'
6
+ # gem 'terrapin'
7
+ # gem 'posix-spawn'
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ ruby-clock (0.8.0.rc2)
5
+ method_source
6
+ rufus-scheduler (~> 3.8)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ concurrent-ruby (1.1.9)
12
+ et-orbi (1.2.5)
13
+ tzinfo
14
+ fugit (1.5.2)
15
+ et-orbi (~> 1.1, >= 1.1.8)
16
+ raabro (~> 1.4)
17
+ method_source (1.0.0)
18
+ raabro (1.4.0)
19
+ rufus-scheduler (3.8.0)
20
+ fugit (~> 1.1, >= 1.1.6)
21
+ tzinfo (2.0.4)
22
+ concurrent-ruby (~> 1.0)
23
+
24
+ PLATFORMS
25
+ arm64-darwin-20
26
+
27
+ DEPENDENCIES
28
+ ruby-clock!
29
+
30
+ BUNDLED WITH
31
+ 2.2.28
@@ -0,0 +1,9 @@
1
+ This is a bare-bones example non-rails app to
2
+ help with dev and also as an example for users.
3
+
4
+ To run:
5
+
6
+ ```
7
+ bundle
8
+ bundle exe clock
9
+ ```
data/exe/clock CHANGED
@@ -8,9 +8,11 @@ class Rufus::Scheduler::Job
8
8
  @identifier ||= begin
9
9
  name || handler.source.split("\n").reject(&:empty?).grep_v(/#.*/)[-2].strip
10
10
  rescue
11
- source_location.join('-')
12
- rescue
13
- 'error-calculating-job-identifier'
11
+ begin
12
+ source_location.join('-')
13
+ rescue
14
+ 'error-calculating-job-identifier'
15
+ end
14
16
  end
15
17
  end
16
18
  end
@@ -18,7 +20,20 @@ end
18
20
  include RubyClock
19
21
 
20
22
  listen_to_signals
23
+ prepare_rake
24
+ schedule.pause
25
+
26
+ load ARGV[0] || 'Clockfile'
21
27
 
22
- load 'Clockfile'
28
+ if defined?(::Rails)
29
+ schedule.instance_eval do
30
+ @old_around_trigger = method :around_trigger
31
+ def around_trigger(job)
32
+ ::Rails.application.reloader.wrap do
33
+ @old_around_trigger.call(job){ yield }
34
+ end
35
+ end
36
+ end
37
+ end
23
38
 
24
39
  run_jobs
@@ -1,3 +1,3 @@
1
1
  module RubyClock
2
- VERSION = "0.6.0"
2
+ VERSION = "0.8.0.rc3"
3
3
  end
data/lib/ruby-clock.rb CHANGED
@@ -3,8 +3,10 @@ require 'rufus-scheduler'
3
3
 
4
4
  module RubyClock
5
5
  def shutdown
6
- puts "Shutting down ruby-clock 🐈️ 👋"
7
- Rufus::Scheduler.singleton.shutdown(wait: 29)
6
+ wait_seconds = ENV['RUBY_CLOCK_SHUTDOWN_WAIT_SECONDS']&.to_i || 29
7
+ puts "Shutting down ruby-clock. Waiting #{wait_seconds} seconds for jobs to finish..."
8
+ schedule.shutdown(wait: wait_seconds)
9
+ puts "...done 🐈️ 👋"
8
10
  end
9
11
 
10
12
  def listen_to_signals
@@ -27,6 +29,81 @@ module RubyClock
27
29
 
28
30
  def run_jobs
29
31
  puts "Starting ruby-clock with #{schedule.jobs.size} jobs"
30
- Rufus::Scheduler.singleton.join
32
+ schedule.resume
33
+ schedule.join
31
34
  end
35
+
36
+ def prepare_rake
37
+ if defined?(::Rails) && Rails.application
38
+ Rails.application.load_tasks
39
+ Rake::Task.tasks.each{|t| t.prerequisites.delete 'environment' }
40
+ @rake_mutex = Mutex.new
41
+ else
42
+ puts <<~MESSAGE
43
+ Because this is not a rails application, we do not know how to load your
44
+ rake tasks. You can do this yourself at the top of your Clockfile if you want
45
+ to run rake tasks from ruby-cron.
46
+ MESSAGE
47
+ end
48
+ end
49
+
50
+ # See https://code.jjb.cc/running-rake-tasks-from-within-ruby-on-rails-code
51
+
52
+ # for tasks that don't have dependencies
53
+ def rake_execute(task)
54
+ Rake::Task[task].execute
55
+ end
56
+
57
+ # If the task doesn't share dependencies with another task,
58
+ # or if it does and you know you'll never run tasks such that any overlap
59
+ def rake_async(task)
60
+ Rake::Task[task].invoke
61
+ ensure
62
+ Rake::Task[task].reenable
63
+ Rake::Task[task].all_prerequisite_tasks.each(&:reenable)
64
+ end
65
+
66
+ # If the task has shared dependencies and you might run more than one at the same time
67
+ # This is the safest option and hence the default.
68
+ def rake(task)
69
+ @rake_mutex.synchronize { rake_async(task) }
70
+ end
71
+
72
+ def shell_runner
73
+ @shell_runner ||= begin
74
+ require 'terrapin'
75
+ require 'posix-spawn'
76
+
77
+ unless Terrapin::CommandLine.runner.class == Terrapin::CommandLine::PosixRunner
78
+ puts <<~MESSAGE
79
+
80
+ 🤷 terrapin and posix-spawn are installed, but for some reason terrapin is
81
+ not using posix-spawn as its runner.
82
+
83
+ MESSAGE
84
+ end
85
+
86
+ puts '🐆 Using terrapin for shell commands.'
87
+ :terrapin
88
+ rescue LoadError
89
+ puts <<~MESSAGE
90
+
91
+ 🦥 Using ruby backticks for shell commands.
92
+ For better performance, install the terrapin and posix-spawn gems.
93
+ See README.md for more info.
94
+
95
+ MESSAGE
96
+ :backticks
97
+ end
98
+ end
99
+
100
+ def shell(command)
101
+ case shell_runner
102
+ when :terrapin
103
+ Terrapin::CommandLine.new(command).run
104
+ when :backticks
105
+ `#{command}`
106
+ end
107
+ end
108
+
32
109
  end
data/release.md ADDED
@@ -0,0 +1,4 @@
1
+ 1. update lib/ruby-clock/version.rb
2
+ 2. update CHANGELOG.md
3
+ 3. commit and push to github
4
+ 3. `rake release`
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-clock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0.rc3
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Bachir
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-14 00:00:00.000000000 Z
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rufus-scheduler
@@ -47,6 +47,7 @@ extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
49
  - ".gitignore"
50
+ - CHANGELOG.md
50
51
  - Gemfile
51
52
  - Gemfile.lock
52
53
  - LICENSE.txt
@@ -54,9 +55,15 @@ files:
54
55
  - Rakefile
55
56
  - bin/console
56
57
  - bin/setup
58
+ - example-app/.gitattributes
59
+ - example-app/Clockfile
60
+ - example-app/Gemfile
61
+ - example-app/Gemfile.lock
62
+ - example-app/README.md
57
63
  - exe/clock
58
64
  - lib/ruby-clock.rb
59
65
  - lib/ruby-clock/version.rb
66
+ - release.md
60
67
  - ruby-clock.gemspec
61
68
  homepage: https://github.com/jjb/ruby-clock
62
69
  licenses:
@@ -75,11 +82,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
75
82
  version: 2.3.0
76
83
  required_rubygems_version: !ruby/object:Gem::Requirement
77
84
  requirements:
78
- - - ">="
85
+ - - ">"
79
86
  - !ruby/object:Gem::Version
80
- version: '0'
87
+ version: 1.3.1
81
88
  requirements: []
82
- rubygems_version: 3.1.6
89
+ rubygems_version: 3.2.22
83
90
  signing_key:
84
91
  specification_version: 4
85
92
  summary: A "clock" process for invoking ruby code within a persistent runtime