sidekiq-cron 0.6.3 → 1.2.0

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
  SHA1:
3
- metadata.gz: 1c9490a07af91904810a5289c0899691f70bb56b
4
- data.tar.gz: 4d79c982c22844a7f7fa887dde61925aaa26e48e
3
+ metadata.gz: cb2f152cb3faf85dbc089e10820fd48d7c23f6ad
4
+ data.tar.gz: 4ced419b5c9ddaeb43a6ebd62221cdbd95eb2c91
5
5
  SHA512:
6
- metadata.gz: c9717f01b61187ffb9cc2024ac3de6a01a1641159ef5f0013f742858a932b01c5a89dcb37abb254484cc1ca9edb6da10cf96fa7d0b2b068199945db18e855c3b
7
- data.tar.gz: a06735e8a699441b6b9a0218e99949710b44dc2a1fdf92725fe865594687e428cd7509efd04023a9a09d5f4580466ab117ad6ccc471ab2797fae804fef9a3ea8
6
+ metadata.gz: d882bd7a34f478fc9ea3eb591c6ffe01df2b360ba501ef2df13aa3d7631f77a97a393bc5a391ec682810766dbfe8790bb8a42ed29fc69a666623753103c4c994
7
+ data.tar.gz: 4bbdf927f3830a9a62e2bf622bf34492555e0a8051f303a0a712eda46a818a5dfd78b5de913e137e39b91f046a05247ae2a133cabe1573fa1b4f21307f721b24
data/.travis.yml CHANGED
@@ -1,7 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.1
4
- - 2.2.2
3
+ - 2.6
4
+ - 2.5
5
+ - 2.4
6
+ - 2.3
7
+ - 2.2
5
8
  services:
6
9
  - redis-server
7
10
  branches:
@@ -13,7 +16,3 @@ notifications:
13
16
  - ondrej@bartas.cz
14
17
  env:
15
18
  travis: 'yes'
16
- matrix:
17
- allow_failures:
18
- - rvm: jruby-19mode
19
- - rvm: rbx-19mode
data/Changes.md CHANGED
@@ -1,3 +1,35 @@
1
+ v 1.2.0
2
+ -------
3
+
4
+ - updated readme
5
+ - fix problem with Sidekiq::Launcher and requiring it when not needed
6
+ - better patching of Sidekiq::Launcher
7
+ - fixed Dockerfile
8
+
9
+ v 1.1.0
10
+ -------
11
+
12
+ - updated readme
13
+ - fix unit tests - changed argument error when getting invalid cron format
14
+ - when fallbacking old job enqueued time use `Time.parse` šwithout format (so ruby can decide best method to parse it)
15
+ - add option `date_as_argument` which will add to your job arguments on last place `Time.now.to_f` when it was eneuqued
16
+ - add option `description` which will allow you to add notes to your jobs so in web view you can see it
17
+ - fixed translations
18
+
19
+ v 1.0.4
20
+ -------
21
+
22
+ - fix problem with upgrading to 1.0.x - parsing last enqued time didn't count with old time format stored in redis
23
+
24
+ v 1.0.0
25
+ -------
26
+
27
+ - use [fugit](https://github.com/floraison/fugit) instead of [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) - API of cron didn't change (rufus scheduler is using fugit)
28
+ - better working with Timezones
29
+ - translations for JA, zh-CN
30
+ - cron without timezone are considered as UTC, to add Timezone to cron use format `* * * * * Europe/Berlin`
31
+ - be aware that this release can change when your jobs are enqueued (for me it didn't change but it is in one project, in other it can shift by different timezone setup)
32
+
1
33
  v 0.6.0
2
34
  -------
3
35
 
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.3.1
1
+ FROM ruby:2.4
2
2
  MAINTAINER Joao Serra <joaopfserra@gmail.com>
3
3
 
4
4
  RUN apt-get update && \
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'sidekiq', '>= 4.2.1'
4
- gem 'rufus-scheduler', '>= 3.3.0'
4
+ gem 'fugit', '~> 1.1'
5
5
 
6
6
  group :development do
7
7
  gem 'bundler'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Sidekiq-Cron [![Gem Version](https://badge.fury.io/rb/sidekiq-cron.svg)](http://badge.fury.io/rb/sidekiq-cron) [![Build Status](https://travis-ci.org/ondrejbartas/sidekiq-cron.svg?branch=master)](https://travis-ci.org/ondrejbartas/sidekiq-cron) [![Coverage Status](https://coveralls.io/repos/ondrejbartas/sidekiq-cron/badge.svg?branch=master)](https://coveralls.io/r/ondrejbartas/sidekiq-cron?branch=master) [![Dependency Status](https://dependencyci.com/github/ondrejbartas/sidekiq-cron/badge)](https://dependencyci.com/github/ondrejbartas/sidekiq-cron)
1
+ Sidekiq-Cron [![Gem Version](https://badge.fury.io/rb/sidekiq-cron.svg)](http://badge.fury.io/rb/sidekiq-cron) [![Build Status](https://travis-ci.org/ondrejbartas/sidekiq-cron.svg?branch=master)](https://travis-ci.org/ondrejbartas/sidekiq-cron) [![Coverage Status](https://coveralls.io/repos/github/ondrejbartas/sidekiq-cron/badge.svg?branch=master)](https://coveralls.io/github/ondrejbartas/sidekiq-cron?branch=master)
2
2
  ================================================================================================================================================================================================================================================================================================================================================================================================================================================
3
3
 
4
4
  [![Join the chat at https://gitter.im/ondrejbartas/sidekiq-cron](https://badges.gitter.im/ondrejbartas/sidekiq-cron.svg)](https://gitter.im/ondrejbartas/sidekiq-cron?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -7,11 +7,11 @@ Sidekiq-Cron [![Gem Version](https://badge.fury.io/rb/sidekiq-cron.svg)](http://
7
7
 
8
8
  A scheduling add-on for [Sidekiq](http://sidekiq.org).
9
9
 
10
- Runs a thread alongside Sidekiq workers to schedule jobs at specified times (using cron notation `* * * * *` parsed by [Rufus-Scheduler](https://github.com/jmettraux/rufus-scheduler), more about [cron notation](http://www.nncron.ru/help/EN/working/cron-format.htm).
10
+ Runs a thread alongside Sidekiq workers to schedule jobs at specified times (using cron notation `* * * * *` parsed by [Fugit](https://github.com/floraison/fugit), more about [cron notation](http://www.nncron.ru/help/EN/working/cron-format.htm).
11
11
 
12
- Checks for new jobs to schedule every 10 seconds and doesn't schedule the same job multiple times when more than one Sidekiq worker is running.
12
+ Checks for new jobs to schedule every 30 seconds and doesn't schedule the same job multiple times when more than one Sidekiq worker is running.
13
13
 
14
- Scheduling jobs are added only when at least one Sidekiq process is running.
14
+ Scheduling jobs are added only when at least one Sidekiq process is running, but it is safe to use Sidekiq-Cron in environments where multiple Sidekiq processes or nodes are running.
15
15
 
16
16
  If you want to know how scheduling work, check out [under the hood](#under-the-hood)
17
17
 
@@ -19,6 +19,11 @@ Works with ActiveJob (Rails 4.2+)
19
19
 
20
20
  You don't need Sidekiq PRO, you can use this gem with plain __Sidekiq__.
21
21
 
22
+ Upgrade from <0.6x to 1.0.x
23
+ ---------------------------
24
+
25
+ Please be aware that sidekiq-cron < 1.0 was relying on rufus-scheduler < 3.5. Using those older sidekiq-cron with rufus-scheduler >= 3.5 ends up with jobs failing on creation. Sidekiq-cron 1.0 includes a patch that switches from rufus-scheduler to rufus-scheduler's core dependency, fugit.
26
+
22
27
  Requirements
23
28
  -----------------
24
29
 
@@ -37,7 +42,7 @@ Installation
37
42
 
38
43
  or add to your `Gemfile`
39
44
 
40
- gem "sidekiq-cron", "~> 0.4.0"
45
+ gem "sidekiq-cron", "~> 1.1"
41
46
 
42
47
 
43
48
  Getting Started
@@ -56,19 +61,25 @@ _Job properties_:
56
61
  #OPTIONAL
57
62
  'queue' => 'name of queue',
58
63
  'args' => '[Array or Hash] of arguments which will be passed to perform method',
64
+ 'date_as_argument' => true, # add the time of execution as last argument of the perform method
59
65
  'active_job' => true, # enqueue job through rails 4.2+ active job interface
60
66
  'queue_name_prefix' => 'prefix', # rails 4.2+ active job queue with prefix
61
- 'queue_name_delimiter' => '.' # rails 4.2+ active job queue with custom delimiter
67
+ 'queue_name_delimiter' => '.', # rails 4.2+ active job queue with custom delimiter
68
+ 'description' => 'A sentence describing what work this job performs.' # Optional
62
69
  }
63
70
  ```
64
71
 
65
72
  ### Time, cron and sidekiq-cron
66
73
 
67
- sidekiq-cron uses [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) to parse the cronline.
68
- By default, the timezone this is evaluated against UTC.
74
+ For testing your cron notation you can use [crontab.guru](https://crontab.guru).
75
+
76
+ sidekiq-cron uses [Fugit](https://github.com/floraison/fugit) to parse the cronline.
77
+ If using Rails, this is evaluated against the timezone configured in Rails, otherwise the default is UTC.
78
+
69
79
  If you want to have your jobs enqueued based on a different time zone you can specify a timezone in the cronline,
70
80
  like this `'0 22 * * 1-5 America/Chicago'`.
71
- See [rufus-scheduler documentation](https://github.com/jmettraux/rufus-scheduler#a-note-about-timezones) for more information.
81
+
82
+ See [rufus-scheduler documentation](https://github.com/jmettraux/rufus-scheduler#a-note-about-timezones) for more information. (note. Rufus scheduler is using Fugit under the hood, so documentation for Rufus Scheduler can help you also)
72
83
 
73
84
  ### What objects/classes can be scheduled
74
85
  #### Sidekiq Worker
@@ -192,7 +203,7 @@ second_job:
192
203
  #initializers/sidekiq.rb
193
204
  schedule_file = "config/schedule.yml"
194
205
 
195
- if File.exists?(schedule_file) && Sidekiq.server?
206
+ if File.exist?(schedule_file) && Sidekiq.server?
196
207
  Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
197
208
  end
198
209
  ```
@@ -263,13 +274,13 @@ before the process forks, causing the following exception
263
274
 
264
275
  Redis::InheritedError: Tried to use a connection from a child process without reconnecting. You need to reconnect to Redis after forking.
265
276
 
266
- to occcur. To avoid this, wrap your job creation in the call to `Sidekiq.configure_server`:
277
+ to occur. To avoid this, wrap your job creation in the call to `Sidekiq.configure_server`:
267
278
 
268
279
  ```ruby
269
280
  Sidekiq.configure_server do |config|
270
281
  schedule_file = "config/schedule.yml"
271
282
 
272
- if File.exists?(schedule_file)
283
+ if File.exist?(schedule_file)
273
284
  Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
274
285
  end
275
286
  end
@@ -288,6 +299,8 @@ Sidekiq-Cron is checking jobs to be enqueued every 30s by default, you can chang
288
299
  Sidekiq.options[:poll_interval] = 10
289
300
  ```
290
301
 
302
+ Sidekiq-Cron is safe to use with multiple sidekiq processes or nodes. It uses a Redis sorted set to determine that only the first process who asks can enqueue scheduled jobs into the queue.
303
+
291
304
  ## Thanks to
292
305
  * [@7korobi](https://github.com/7korobi)
293
306
  * [@antulik](https://github.com/antulik)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.3
1
+ 1.2.0
data/docker-compose.yml CHANGED
@@ -18,4 +18,6 @@ services:
18
18
  - redis:redis.test
19
19
  depends_on:
20
20
  - common
21
- command: dockerize -wait tcp://redis.test:6379 -timeout 60s rake test
21
+ command: dockerize -wait tcp://redis.test:6379 -timeout 60s bundle exec rake test
22
+ volumes:
23
+ - .:/sidekiq-cron
@@ -1,6 +1,6 @@
1
+ require 'fugit'
1
2
  require 'sidekiq'
2
3
  require 'sidekiq/util'
3
- require 'rufus-scheduler'
4
4
  require 'sidekiq/cron/support'
5
5
 
6
6
  module Sidekiq
@@ -12,6 +12,7 @@ module Sidekiq
12
12
 
13
13
  #how long we would like to store informations about previous enqueues
14
14
  REMEMBER_THRESHOLD = 24 * 60 * 60
15
+ LAST_ENQUEUE_TIME_FORMAT = '%Y-%m-%d %H:%M:%S %z'
15
16
 
16
17
  #crucial part of whole enquing job
17
18
  def should_enque? time
@@ -46,7 +47,7 @@ module Sidekiq
46
47
 
47
48
  #enque cron job to queue
48
49
  def enque! time = Time.now.utc
49
- @last_enqueue_time = time
50
+ @last_enqueue_time = time.strftime(LAST_ENQUEUE_TIME_FORMAT)
50
51
 
51
52
  klass_const =
52
53
  begin
@@ -55,21 +56,23 @@ module Sidekiq
55
56
  nil
56
57
  end
57
58
 
58
- if klass_const
59
- if defined?(ActiveJob::Base) && klass_const < ActiveJob::Base
60
- enqueue_active_job(klass_const)
61
- else
62
- enqueue_sidekiq_worker(klass_const)
63
- end
64
- else
65
- if @active_job
66
- Sidekiq::Client.push(active_job_message)
59
+ jid =
60
+ if klass_const
61
+ if defined?(ActiveJob::Base) && klass_const < ActiveJob::Base
62
+ enqueue_active_job(klass_const).try :provider_job_id
63
+ else
64
+ enqueue_sidekiq_worker(klass_const)
65
+ end
67
66
  else
68
- Sidekiq::Client.push(sidekiq_worker_message)
67
+ if @active_job
68
+ Sidekiq::Client.push(active_job_message)
69
+ else
70
+ Sidekiq::Client.push(sidekiq_worker_message)
71
+ end
69
72
  end
70
- end
71
73
 
72
74
  save_last_enqueue_time
75
+ add_jid_history jid
73
76
  logger.debug { "enqueued #{@name}: #{@message}" }
74
77
  end
75
78
 
@@ -81,14 +84,10 @@ module Sidekiq
81
84
 
82
85
  def enqueue_active_job(klass_const)
83
86
  klass_const.set(queue: @queue).perform_later(*@args)
84
-
85
- true
86
87
  end
87
88
 
88
89
  def enqueue_sidekiq_worker(klass_const)
89
90
  klass_const.set(queue: queue_name_with_prefix).perform_async(*@args)
90
-
91
- true
92
91
  end
93
92
 
94
93
  # siodekiq worker message
@@ -123,6 +122,7 @@ module Sidekiq
123
122
  def active_job_message
124
123
  {
125
124
  'class' => 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper',
125
+ 'wrapped' => @klass,
126
126
  'queue' => @queue_name_with_prefix,
127
127
  'description' => @description,
128
128
  'args' => [{
@@ -273,13 +273,14 @@ module Sidekiq
273
273
 
274
274
  #set last enqueue time - from args or from existing job
275
275
  if args['last_enqueue_time'] && !args['last_enqueue_time'].empty?
276
- @last_enqueue_time = Time.parse(args['last_enqueue_time'])
276
+ @last_enqueue_time = parse_enqueue_time(args['last_enqueue_time'])
277
277
  else
278
278
  @last_enqueue_time = last_enqueue_time_from_redis
279
279
  end
280
280
 
281
281
  #get right arguments for job
282
282
  @args = args["args"].nil? ? [] : parse_args( args["args"] )
283
+ @args += [Time.now.to_f] if args["date_as_argument"]
283
284
 
284
285
  @active_job = args["active_job"] == true || ("#{args["active_job"]}" =~ (/^(true|t|yes|y|1)$/i)) == 0 || false
285
286
  @active_job_queue_name_prefix = args["queue_name_prefix"]
@@ -347,6 +348,12 @@ module Sidekiq
347
348
  !enabled?
348
349
  end
349
350
 
351
+ def pretty_message
352
+ JSON.pretty_generate Sidekiq.load_json(message)
353
+ rescue JSON::ParserError
354
+ message
355
+ end
356
+
350
357
  def status_from_redis
351
358
  out = "enabled"
352
359
  if fetch_missing_args
@@ -362,12 +369,24 @@ module Sidekiq
362
369
  out = nil
363
370
  if fetch_missing_args
364
371
  Sidekiq.redis do |conn|
365
- out = Time.parse(conn.hget(redis_key, "last_enqueue_time")) rescue nil
372
+ out = parse_enqueue_time(conn.hget(redis_key, "last_enqueue_time")) rescue nil
366
373
  end
367
374
  end
368
375
  out
369
376
  end
370
377
 
378
+ def jid_history_from_redis
379
+ out =
380
+ Sidekiq.redis do |conn|
381
+ conn.lrange(jid_history_key, 0, -1) rescue nil
382
+ end
383
+
384
+ # returns nil if out nil
385
+ out && out.map do |jid_history_raw|
386
+ Sidekiq.load_json jid_history_raw
387
+ end
388
+ end
389
+
371
390
  #export job data to hash
372
391
  def to_hash
373
392
  {
@@ -390,7 +409,7 @@ module Sidekiq
390
409
  end
391
410
 
392
411
  def valid?
393
- #clear previos errors
412
+ #clear previous errors
394
413
  @errors = []
395
414
 
396
415
  errors << "'name' must be set" if @name.nil? || @name.size == 0
@@ -398,21 +417,15 @@ module Sidekiq
398
417
  errors << "'cron' must be set"
399
418
  else
400
419
  begin
401
- cron = Rufus::Scheduler::CronLine.new(@cron)
402
- cron.next_time(Time.now.utc).utc
403
- rescue Exception => e
404
- #fix for different versions of cron-parser
405
- if e.message == "Bad Vixie-style specification bad"
406
- errors << "'cron' -> #{@cron}: not a valid cronline"
407
- else
408
- errors << "'cron' -> #{@cron}: #{e.message}"
409
- end
420
+ @parsed_cron = Fugit.do_parse_cron(@cron)
421
+ rescue => e
422
+ errors << "'cron' -> #{@cron.inspect} -> #{e.class}: #{e.message}"
410
423
  end
411
424
  end
412
425
 
413
426
  errors << "'klass' (or class) must be set" unless klass_valid
414
427
 
415
- !errors.any?
428
+ errors.empty?
416
429
  end
417
430
 
418
431
  def klass_valid
@@ -460,6 +473,20 @@ module Sidekiq
460
473
  end
461
474
  end
462
475
 
476
+ def add_jid_history(jid)
477
+ jid_history = {
478
+ jid: jid,
479
+ enqueued: @last_enqueue_time
480
+ }
481
+ @history_size ||= (Sidekiq.options[:cron_history_size] || 10).to_i - 1
482
+ Sidekiq.redis do |conn|
483
+ conn.lpush jid_history_key,
484
+ Sidekiq.dump_json(jid_history)
485
+ # keep only last 10 entries in a fifo manner
486
+ conn.ltrim jid_history_key, 0, @history_size
487
+ end
488
+ end
489
+
463
490
  # remove job from cron jobs by name
464
491
  # input:
465
492
  # first arg: name (string) - name of job (must be same - case sensitive)
@@ -471,6 +498,9 @@ module Sidekiq
471
498
  #delete runned timestamps
472
499
  conn.del job_enqueued_key
473
500
 
501
+ # delete jid_history
502
+ conn.del jid_history_key
503
+
474
504
  #delete main job
475
505
  conn.del redis_key
476
506
  end
@@ -496,7 +526,7 @@ module Sidekiq
496
526
  # Parse cron specification '* * * * *' and returns
497
527
  # time when last run should be performed
498
528
  def last_time now = Time.now.utc
499
- Rufus::Scheduler::CronLine.new(@cron).previous_time(now.utc).utc
529
+ parsed_cron.previous_time(now.utc).utc
500
530
  end
501
531
 
502
532
  def formated_enqueue_time now = Time.now.utc
@@ -525,6 +555,10 @@ module Sidekiq
525
555
 
526
556
  private
527
557
 
558
+ def parsed_cron
559
+ @parsed_cron ||= Fugit.parse_cron(@cron)
560
+ end
561
+
528
562
  def not_enqueued_after?(time)
529
563
  @last_enqueue_time.nil? || @last_enqueue_time.to_i < last_time(time).to_i
530
564
  end
@@ -550,8 +584,16 @@ module Sidekiq
550
584
  end
551
585
  end
552
586
 
587
+ def parse_enqueue_time(timestamp)
588
+ DateTime.strptime(timestamp, LAST_ENQUEUE_TIME_FORMAT).to_time.utc
589
+ rescue ArgumentError
590
+ DateTime.parse(timestamp).to_time.utc
591
+ end
592
+
553
593
  def not_past_scheduled_time?(current_time)
554
- last_cron_time = Rufus::Scheduler::CronLine.new(@cron).previous_time(current_time).utc
594
+ last_cron_time = parsed_cron.previous_time(current_time).utc
595
+ # or could it be?
596
+ #last_cron_time = last_time(current_time)
555
597
  return false if (current_time.to_i - last_cron_time.to_i) > 60
556
598
  true
557
599
  end
@@ -577,12 +619,20 @@ module Sidekiq
577
619
  "cron_job:#{name}:enqueued"
578
620
  end
579
621
 
622
+ def self.jid_history_key name
623
+ "cron_job:#{name}:jid_history"
624
+ end
625
+
580
626
  # Redis key for storing one cron job run times
581
627
  # (when poller added job to queue)
582
628
  def job_enqueued_key
583
629
  self.class.job_enqueued_key @name
584
630
  end
585
631
 
632
+ def jid_history_key
633
+ self.class.jid_history_key @name
634
+ end
635
+
586
636
  # Give Hash
587
637
  # returns array for using it for redis.hmset
588
638
  def hash_to_redis hash