mirror of
				https://github.com/endofunky/sidetiq.git
				synced 2022-11-09 13:53:30 -05:00 
			
		
		
		
	Initial commit.
This commit is contained in:
		
						commit
						08b76a3737
					
				
					 22 changed files with 553 additions and 0 deletions
				
			
		
							
								
								
									
										9
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
lib/*.bundle
 | 
			
		||||
coverage
 | 
			
		||||
rdoc
 | 
			
		||||
doc
 | 
			
		||||
.yardoc
 | 
			
		||||
.bundle
 | 
			
		||||
Gemfile.lock
 | 
			
		||||
pkg
 | 
			
		||||
tmp
 | 
			
		||||
							
								
								
									
										14
									
								
								Gemfile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Gemfile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
source 'https://rubygems.org'
 | 
			
		||||
 | 
			
		||||
group :development do
 | 
			
		||||
  gem 'rake'
 | 
			
		||||
  gem 'rake-compiler'
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
group :test do
 | 
			
		||||
  gem 'simplecov'
 | 
			
		||||
  gem 'mocha'
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
gemspec
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								LICENSE
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								LICENSE
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
Copyright (C) 2012 by Tobias Svensson <tobias@musicglue.com>
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in
 | 
			
		||||
all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
THE SOFTWARE.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										90
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
Sidetiq
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
Recurring jobs for [Sidekiq](http://mperham.github.com/sidekiq/).
 | 
			
		||||
 | 
			
		||||
## DESCRIPTION
 | 
			
		||||
 | 
			
		||||
Sidetiq provides a simple API for defining recurring workers for Sidekiq.
 | 
			
		||||
 | 
			
		||||
- Flexible DSL based on [ice_cube](http://seejohnrun.github.com/ice_cube/)
 | 
			
		||||
- High-resolution timer using `clock_gettime(3)` (or `mach_absolute_time()` on
 | 
			
		||||
  Apple Mac OS X), allowing for accurate sub-second clock ticks.
 | 
			
		||||
 | 
			
		||||
## DEPENDENCIES
 | 
			
		||||
 | 
			
		||||
- [Sidekiq](http://mperham.github.com/sidekiq/)
 | 
			
		||||
- [ice_cube](http://seejohnrun.github.com/ice_cube/)
 | 
			
		||||
 | 
			
		||||
## INSTALLATION
 | 
			
		||||
 | 
			
		||||
The best way to install Sidetiq is with RubyGems:
 | 
			
		||||
 | 
			
		||||
    $ [sudo] gem install sidetiq
 | 
			
		||||
 | 
			
		||||
If you're installing from source, you can use [Bundler](http://gembundler.com/)
 | 
			
		||||
to pick up all the gems ([more info](http://gembundler.com/bundle_install.html)):
 | 
			
		||||
 | 
			
		||||
    $ bundle install
 | 
			
		||||
 | 
			
		||||
## GETTING STARTED
 | 
			
		||||
 | 
			
		||||
Defining recurring jobs is simple:
 | 
			
		||||
 | 
			
		||||
```ruby
 | 
			
		||||
class MyWorker
 | 
			
		||||
  include Sidekiq::Worker
 | 
			
		||||
  include Sidetiq::Schedulable
 | 
			
		||||
 | 
			
		||||
  # Every other month on the first monday and last tuesday at 12 o'clock.
 | 
			
		||||
  tiq { monthly(2).day_of_week(1 => [1], 2 => [-1]).hour_of_day(12) }
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It also is possible to define multiple scheduling rules for a worker:
 | 
			
		||||
 | 
			
		||||
```ruby
 | 
			
		||||
class MyWorker
 | 
			
		||||
  include Sidekiq::Worker
 | 
			
		||||
  include Sidetiq::Schedulable
 | 
			
		||||
 | 
			
		||||
  tiq do
 | 
			
		||||
    # Every third year in March
 | 
			
		||||
    yearly(3).month_of_year(:march)
 | 
			
		||||
 | 
			
		||||
    # Every fourth year in Februrary
 | 
			
		||||
    yearly(2).month_of_year(:februrary)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The first time the tiq method is called, Sidetiq will automatically spin up
 | 
			
		||||
it's clock thread and enqueue jobs for their next occurrence using
 | 
			
		||||
`#perform_at`. Note that by default Sidekiq only polls every 15 seconds.
 | 
			
		||||
 | 
			
		||||
If workers are spread across multiple machines multiple jobs might be enqueued
 | 
			
		||||
at the same time. This can be avoided by using a locking library for Sidekiq,
 | 
			
		||||
such as [sidekiq-unique-jobs](https://github.com/form26/sidekiq-unique-jobs).
 | 
			
		||||
 | 
			
		||||
## CONTRIBUTE
 | 
			
		||||
 | 
			
		||||
If you'd like to contribute to Sidetiq, start by forking my repo on GitHub:
 | 
			
		||||
 | 
			
		||||
[http://github.com/tobiassvn/sidetiq](http://github.com/tobiassvn/sidetiq)
 | 
			
		||||
 | 
			
		||||
To get all of the dependencies, install the gem first. The best way to get
 | 
			
		||||
your changes merged back into core is as follows:
 | 
			
		||||
 | 
			
		||||
1. Clone down your fork
 | 
			
		||||
1. Create a thoughtfully named topic branch to contain your change
 | 
			
		||||
1. Write some code
 | 
			
		||||
1. Add tests and make sure everything still passes by running `rake`
 | 
			
		||||
1. If you are adding new functionality, document it in the README
 | 
			
		||||
1. Do not change the version number, I will do that on my end
 | 
			
		||||
1. If necessary, rebase your commits into logical chunks, without errors
 | 
			
		||||
1. Push the branch up to GitHub
 | 
			
		||||
1. Send a pull request to the tobiassvn/sidetiq project.
 | 
			
		||||
 | 
			
		||||
## LICENSE
 | 
			
		||||
 | 
			
		||||
Sidetiq is released under the MIT License. See LICENSE for further details.
 | 
			
		||||
							
								
								
									
										11
									
								
								Rakefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Rakefile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
require 'bundler/gem_tasks'
 | 
			
		||||
require 'rake/testtask'
 | 
			
		||||
require 'rake/extensiontask'
 | 
			
		||||
 | 
			
		||||
Rake::ExtensionTask.new('sidetiq_ext')
 | 
			
		||||
 | 
			
		||||
Rake::TestTask.new do |t|
 | 
			
		||||
  t.pattern = 'test/**/test_*.rb'
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
task default: :test
 | 
			
		||||
							
								
								
									
										19
									
								
								examples/simple.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								examples/simple.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
require 'sidetiq'
 | 
			
		||||
 | 
			
		||||
# We're only loading this so we don't actually have to connect to redis.
 | 
			
		||||
require 'sidekiq/testing'
 | 
			
		||||
 | 
			
		||||
class ExampleWorker
 | 
			
		||||
  include Sidekiq::Worker
 | 
			
		||||
  include Sidetiq::Schedulable
 | 
			
		||||
 | 
			
		||||
  def self.perform_at(time)
 | 
			
		||||
    puts "Enqueued to run at #{time}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Run every 2 seconds
 | 
			
		||||
  tiq { secondly(2) }
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
puts "Hit C-c to quit."
 | 
			
		||||
sleep 1000000
 | 
			
		||||
							
								
								
									
										4
									
								
								ext/sidetiq_ext/extconf.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								ext/sidetiq_ext/extconf.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
require 'rbconfig'
 | 
			
		||||
require 'mkmf'
 | 
			
		||||
create_makefile('sidetiq_ext')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										97
									
								
								ext/sidetiq_ext/sidetiq_ext.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								ext/sidetiq_ext/sidetiq_ext.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,97 @@
 | 
			
		|||
#include <ruby.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include "sidetiq_ext.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <sys/resource.h>
 | 
			
		||||
#include <mach/mach.h>
 | 
			
		||||
#include <mach/clock.h>
 | 
			
		||||
#include <mach/mach_time.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sched.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
VALUE msidetiq;
 | 
			
		||||
VALUE esidetiq_error;
 | 
			
		||||
VALUE csidetiq_clock;
 | 
			
		||||
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
static mach_timebase_info_data_t clock_gettime_inf;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
        CLOCK_REALTIME,
 | 
			
		||||
        CLOCK_MONOTONIC,
 | 
			
		||||
        CLOCK_PROCESS_CPUTIME_ID,
 | 
			
		||||
        CLOCK_THREAD_CPUTIME_ID
 | 
			
		||||
} clockid_t;
 | 
			
		||||
 | 
			
		||||
int clock_gettime(clockid_t clk_id, struct timespec *tp)
 | 
			
		||||
{
 | 
			
		||||
        kern_return_t ret;
 | 
			
		||||
        clock_serv_t clk;
 | 
			
		||||
        clock_id_t clk_serv_id;
 | 
			
		||||
        mach_timespec_t tm;
 | 
			
		||||
        uint64_t start, end, delta, nano;
 | 
			
		||||
        int retval = -1;
 | 
			
		||||
 | 
			
		||||
        switch (clk_id) {
 | 
			
		||||
                case CLOCK_REALTIME:
 | 
			
		||||
                case CLOCK_MONOTONIC:
 | 
			
		||||
                        clk_serv_id = clk_id == CLOCK_REALTIME ? CALENDAR_CLOCK : SYSTEM_CLOCK;
 | 
			
		||||
                        if (KERN_SUCCESS == (ret = host_get_clock_service(mach_host_self(), clk_serv_id, &clk))) {
 | 
			
		||||
                                if (KERN_SUCCESS == (ret = clock_get_time(clk, &tm))) {
 | 
			
		||||
                                        tp->tv_sec  = tm.tv_sec;
 | 
			
		||||
                                        tp->tv_nsec = tm.tv_nsec;
 | 
			
		||||
                                        retval = 0;
 | 
			
		||||
                                }
 | 
			
		||||
                        }
 | 
			
		||||
                        if (KERN_SUCCESS != ret) {
 | 
			
		||||
                                errno = EINVAL;
 | 
			
		||||
                                retval = -1;
 | 
			
		||||
                        }
 | 
			
		||||
                break;
 | 
			
		||||
                case CLOCK_PROCESS_CPUTIME_ID:
 | 
			
		||||
                case CLOCK_THREAD_CPUTIME_ID:
 | 
			
		||||
                        start = mach_absolute_time();
 | 
			
		||||
                        if (clk_id == CLOCK_PROCESS_CPUTIME_ID) {
 | 
			
		||||
                                getpid();
 | 
			
		||||
                        } else {
 | 
			
		||||
                                sched_yield();
 | 
			
		||||
                        }
 | 
			
		||||
                        end = mach_absolute_time();
 | 
			
		||||
                        delta = end - start;
 | 
			
		||||
                        if (0 == clock_gettime_inf.denom) {
 | 
			
		||||
                                mach_timebase_info(&clock_gettime_inf);
 | 
			
		||||
                        }
 | 
			
		||||
                        nano = delta * clock_gettime_inf.numer / clock_gettime_inf.denom;
 | 
			
		||||
                        tp->tv_sec = nano * 1e-9;
 | 
			
		||||
                        tp->tv_nsec = nano - (tp->tv_sec * 1e9);
 | 
			
		||||
                        retval = 0;
 | 
			
		||||
                break;
 | 
			
		||||
                default:
 | 
			
		||||
                        errno = EINVAL;
 | 
			
		||||
                        retval = -1;
 | 
			
		||||
        }
 | 
			
		||||
        return retval;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static VALUE sidetiq_gettime(VALUE self)
 | 
			
		||||
{
 | 
			
		||||
        struct timespec time;
 | 
			
		||||
        assert(clock_gettime(CLOCK_REALTIME, &time) == 0);
 | 
			
		||||
        return rb_time_nano_new(time.tv_sec, time.tv_nsec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Init_sidetiq_ext()
 | 
			
		||||
{
 | 
			
		||||
        msidetiq = rb_define_module("Sidetiq");
 | 
			
		||||
        esidetiq_error = rb_define_class_under(msidetiq, "Error", rb_eStandardError);
 | 
			
		||||
        csidetiq_clock = rb_define_class_under(msidetiq, "Clock", rb_cObject);
 | 
			
		||||
        rb_define_method(csidetiq_clock, "gettime", sidetiq_gettime, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								ext/sidetiq_ext/sidetiq_ext.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								ext/sidetiq_ext/sidetiq_ext.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
#ifndef __SIDETIQ_EXT_H__
 | 
			
		||||
#define __SIDETIQ_EXT_H__
 | 
			
		||||
#include <ruby.h>
 | 
			
		||||
 | 
			
		||||
typedef uint64_t sidetiq_time_t;
 | 
			
		||||
 | 
			
		||||
void Init_sidetiq_ext();
 | 
			
		||||
static VALUE sidetiq_gettime(VALUE self);
 | 
			
		||||
 | 
			
		||||
/* module Sidetiq */
 | 
			
		||||
extern VALUE msidetiq;
 | 
			
		||||
 | 
			
		||||
/* class Sidetiq::Error < StandardError */
 | 
			
		||||
extern VALUE esidetiq_error;
 | 
			
		||||
 | 
			
		||||
/* class Sidetiq::Clock */
 | 
			
		||||
extern VALUE csidetiq_clock;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										19
									
								
								lib/sidetiq.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/sidetiq.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
# stdlib
 | 
			
		||||
require 'singleton'
 | 
			
		||||
require 'monitor'
 | 
			
		||||
require 'ostruct'
 | 
			
		||||
 | 
			
		||||
# gems
 | 
			
		||||
require 'sidekiq'
 | 
			
		||||
require 'ice_cube'
 | 
			
		||||
 | 
			
		||||
# c extensions
 | 
			
		||||
require 'sidetiq_ext'
 | 
			
		||||
 | 
			
		||||
# internal
 | 
			
		||||
require 'sidetiq/config'
 | 
			
		||||
require 'sidetiq/clock'
 | 
			
		||||
require 'sidetiq/schedule'
 | 
			
		||||
require 'sidetiq/schedulable'
 | 
			
		||||
require 'sidetiq/version'
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								lib/sidetiq/class_methods.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/sidetiq/class_methods.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
module Sidetiq
 | 
			
		||||
  module Schedulable
 | 
			
		||||
    module ClassMethods
 | 
			
		||||
      def tiq(&block)
 | 
			
		||||
        Sidetiq::Scheduler.instance.instance_eval(&block)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.included(klass)
 | 
			
		||||
      klass.extend(Sidetiq::Schedulable::ClassMethods)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										55
									
								
								lib/sidetiq/clock.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								lib/sidetiq/clock.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
module Sidetiq
 | 
			
		||||
  configure do |config|
 | 
			
		||||
    config.priority = Thread.current.priority
 | 
			
		||||
    config.resolution = 0.2
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class Clock
 | 
			
		||||
    include Singleton
 | 
			
		||||
    include MonitorMixin
 | 
			
		||||
 | 
			
		||||
    attr_reader :schedules
 | 
			
		||||
 | 
			
		||||
    def initialize
 | 
			
		||||
      super
 | 
			
		||||
      @schedules = {}
 | 
			
		||||
      start!
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def schedule_for(worker)
 | 
			
		||||
      schedules[worker] ||= Sidetiq::Schedule.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def tick
 | 
			
		||||
      @tick = gettime
 | 
			
		||||
 | 
			
		||||
      synchronize do
 | 
			
		||||
        schedules.each do |worker, schedule|
 | 
			
		||||
          if schedule.schedule_next?(@tick)
 | 
			
		||||
            occurrence = schedule.next_occurrence
 | 
			
		||||
            Sidekiq.logger.info "Sidetiq::Clock enqueue #{worker.name} (at: #{occurrence.to_s})"
 | 
			
		||||
            worker.perform_at(occurrence)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def start!
 | 
			
		||||
      Sidekiq.logger.info "Sidetiq::Clock start"
 | 
			
		||||
      thr = Thread.start { clock { tick } }
 | 
			
		||||
      thr.abort_on_exception = true
 | 
			
		||||
      thr.priority = Sidetiq.config.resolution
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def clock
 | 
			
		||||
      loop do
 | 
			
		||||
        yield
 | 
			
		||||
        Thread.pass
 | 
			
		||||
        sleep Sidetiq.config.resolution
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								lib/sidetiq/config.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								lib/sidetiq/config.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
module Sidetiq
 | 
			
		||||
  class << self
 | 
			
		||||
    attr_writer :config
 | 
			
		||||
 | 
			
		||||
    def configure
 | 
			
		||||
      yield config
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def config
 | 
			
		||||
      @config ||= OpenStruct.new
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								lib/sidetiq/schedulable.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/sidetiq/schedulable.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
module Sidetiq
 | 
			
		||||
  module Schedulable
 | 
			
		||||
    module ClassMethods
 | 
			
		||||
      def tiq(&block)
 | 
			
		||||
        clock  = Sidetiq::Clock.instance
 | 
			
		||||
        worker = block.send(:binding).eval('self')
 | 
			
		||||
 | 
			
		||||
        clock.synchronize do
 | 
			
		||||
          clock.schedule_for(worker).instance_eval(&block)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def self.included(klass)
 | 
			
		||||
      klass.extend(Sidetiq::Schedulable::ClassMethods)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								lib/sidetiq/schedule.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/sidetiq/schedule.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
module Sidetiq
 | 
			
		||||
  class Schedule < IceCube::Schedule
 | 
			
		||||
    def method_missing(meth, *args, &block)
 | 
			
		||||
      if IceCube::Rule.respond_to?(meth)
 | 
			
		||||
        rule = IceCube::Rule.send(meth, *args, &block)
 | 
			
		||||
        add_recurrence_rule(rule)
 | 
			
		||||
        rule
 | 
			
		||||
      else
 | 
			
		||||
        super
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def schedule_next?(time)
 | 
			
		||||
      if @last_scheduled != (no = next_occurrence(time))
 | 
			
		||||
        @last_scheduled = no
 | 
			
		||||
        return true
 | 
			
		||||
      end
 | 
			
		||||
      false
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								lib/sidetiq/version.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/sidetiq/version.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
module Sidetiq
 | 
			
		||||
  module VERSION
 | 
			
		||||
    MAJOR = 0
 | 
			
		||||
    MINOR = 1
 | 
			
		||||
    PATCH = 0
 | 
			
		||||
 | 
			
		||||
    STRING = [MAJOR, MINOR, PATCH].compact.join('.')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								sidetiq.gemspec
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								sidetiq.gemspec
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
# -*- encoding: utf-8 -*-
 | 
			
		||||
lib = File.expand_path(File.join('..', 'lib'), __FILE__)
 | 
			
		||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
 | 
			
		||||
require 'sidetiq/version'
 | 
			
		||||
 | 
			
		||||
Gem::Specification.new do |gem|
 | 
			
		||||
  gem.name          = "sidetiq"
 | 
			
		||||
  gem.version       = Sidetiq::VERSION::STRING
 | 
			
		||||
  gem.authors       = ["Tobias Svensson"]
 | 
			
		||||
  gem.email         = ["tob@tobiassvensson.co.uk"]
 | 
			
		||||
  gem.description   = "High-resolution job scheduler for Sidekiq"
 | 
			
		||||
  gem.summary       = gem.description
 | 
			
		||||
  gem.homepage      = "http://github.com/tobiassvn/sidetiq"
 | 
			
		||||
  gem.license       = "MIT"
 | 
			
		||||
 | 
			
		||||
  gem.files         = `git ls-files`.split($/)
 | 
			
		||||
  gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
 | 
			
		||||
  gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
 | 
			
		||||
  gem.require_paths = ["lib"]
 | 
			
		||||
  gem.extensions    = ['ext/sidetiq_ext/extconf.rb']
 | 
			
		||||
 | 
			
		||||
  gem.add_dependency 'sidekiq'
 | 
			
		||||
  gem.add_dependency 'ice_cube'
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										16
									
								
								test/helper.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/helper.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
require 'simplecov'
 | 
			
		||||
SimpleCov.start { add_filter "/test/" }
 | 
			
		||||
require 'minitest/autorun'
 | 
			
		||||
require 'mocha/setup'
 | 
			
		||||
require 'sidetiq'
 | 
			
		||||
require 'sidekiq/testing'
 | 
			
		||||
 | 
			
		||||
# Stub out Clock#start! so we don't actually loop
 | 
			
		||||
module Sidetiq
 | 
			
		||||
  class Clock
 | 
			
		||||
    def start!; end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# Keep the test output clean
 | 
			
		||||
Sidekiq.logger = Logger.new(nil)
 | 
			
		||||
							
								
								
									
										12
									
								
								test/test_clock.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/test_clock.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
require_relative 'helper'
 | 
			
		||||
 | 
			
		||||
class TestClock < MiniTest::Unit::TestCase
 | 
			
		||||
  def test_gettime_seconds
 | 
			
		||||
    assert_equal Sidetiq::Clock.instance.gettime.tv_sec, Time.now.tv_sec
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_gettime_nsec
 | 
			
		||||
    refute_nil Sidetiq::Clock.instance.gettime.tv_nsec
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								test/test_errors.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/test_errors.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
require_relative 'helper'
 | 
			
		||||
 | 
			
		||||
class TestErrors < MiniTest::Unit::TestCase
 | 
			
		||||
  def test_error_superclass
 | 
			
		||||
    assert_equal StandardError, Sidetiq::Error.superclass
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										37
									
								
								test/test_sidetiq.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								test/test_sidetiq.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
require_relative 'helper'
 | 
			
		||||
 | 
			
		||||
class TestSidetiq < MiniTest::Unit::TestCase
 | 
			
		||||
  class Worker
 | 
			
		||||
    include Sidekiq::Worker
 | 
			
		||||
    include Sidetiq::Schedulable
 | 
			
		||||
 | 
			
		||||
    tiq do
 | 
			
		||||
      daily.hour_of_day(0)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def clock
 | 
			
		||||
    @clock ||= Sidetiq::Clock.instance
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def tick
 | 
			
		||||
    clock.tick
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_scheduling
 | 
			
		||||
    assert_equal 0, Worker.jobs.size # sanity
 | 
			
		||||
 | 
			
		||||
    clock.stubs(:gettime).returns(Time.now + (24 * 60 * 60))
 | 
			
		||||
    tick
 | 
			
		||||
    assert_equal 1, Worker.jobs.size
 | 
			
		||||
 | 
			
		||||
    clock.stubs(:gettime).returns(Time.now + (2 * 24 * 60 * 60))
 | 
			
		||||
    tick
 | 
			
		||||
    assert_equal 2, Worker.jobs.size
 | 
			
		||||
 | 
			
		||||
    clock.stubs(:gettime).returns(Time.now + (2 * 24 * 60 * 60 + 1))
 | 
			
		||||
    tick
 | 
			
		||||
    assert_equal 2, Worker.jobs.size
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								test/test_version.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								test/test_version.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
require_relative 'helper'
 | 
			
		||||
 | 
			
		||||
class TestVersion < MiniTest::Unit::TestCase
 | 
			
		||||
  def test_major
 | 
			
		||||
    assert_instance_of Fixnum, Sidetiq::VERSION::MAJOR
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_minor
 | 
			
		||||
    assert_instance_of Fixnum, Sidetiq::VERSION::MINOR
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_patch
 | 
			
		||||
    assert_instance_of Fixnum, Sidetiq::VERSION::PATCH
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_string
 | 
			
		||||
    assert_equal Sidetiq::VERSION::STRING, [Sidetiq::VERSION::MAJOR,
 | 
			
		||||
      Sidetiq::VERSION::MINOR, Sidetiq::VERSION::PATCH].compact.join('.')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue