Coder Social home page Coder Social logo

clockwork's Introduction

This fork is no longer maintained, maybe try this one: https://github.com/Rykian/clockwork


Clockwork - a clock process to replace cron

Cron is non-ideal for running scheduled application tasks, especially in an app deployed to multiple machines. More details.

Clockwork is a cron replacement. It runs as a lightweight, long-running Ruby process which sits alongside your web processes (Mongrel/Thin) and your worker processes (DJ/Resque/Minion/Stalker) to schedule recurring work at particular times or dates. For example, refreshing feeds on an hourly basis, or send reminder emails on a nightly basis, or generating invoices once a month on the 1st.

Quickstart

Create clock.rb:

require 'clockwork'
include Clockwork

handler do |job|
  puts "Running #{job}"
end

every(10.seconds, 'frequent.job')
every(3.minutes, 'less.frequent.job')
every(1.hour, 'hourly.job')

every(1.day, 'midnight.job', :at => '00:00')

Run it with the clockwork binary:

$ clockwork clock.rb
Starting clock for 4 events: [ frequent.job less.frequent.job hourly.job midnight.job ]
Triggering frequent.job

Use with queueing

The clock process only makes sense as a place to schedule work to be done, not to do the work. It avoids locking by running as a single process, but this makes it impossible to parallelize. For doing the work, you should be using a job queueing system, such as Delayed Job, Beanstalk/Stalker, RabbitMQ/Minion, or Resque. This design allows a simple clock process with no locks, but also offers near infinite horizontal scalability.

For example, if you're using Beanstalk/Staker:

require 'stalker'

handler { |job| Stalker.enqueue(job) }

every(1.hour, 'feeds.refresh')
every(1.day, 'reminders.send', :at => '01:30')

Using a queueing system which doesn't require that your full application be loaded is preferable, because the clock process can keep a tiny memory footprint. If you're using DJ or Resque, however, you can go ahead and load your full application enviroment, and use per-event blocks to call DJ or Resque enqueue methods. For example, with DJ/Rails:

require 'config/boot'
require 'config/environment'

every(1.hour, 'feeds.refresh') { Feed.send_later(:refresh) }
every(1.day, 'reminders.send', :at => '01:30') { Reminder.send_later(:send_reminders) }

Anatomy of a clock file

clock.rb is standard Ruby. Since we include the Clockwork module (the clockwork binary does this automatically, or you can do it explicitly), this exposes a small DSL ("handler" and "every") to define the handler for events, and then the events themselves.

The handler typically looks like this:

handler { |job| enqueue_your_job(job) }

This block will be invoked every time an event is triggered, with the job name passed in. In most cases, you should be able to pass the job name directly through to your queueing system.

The second part of the file are the events, which roughly resembles a crontab:

every(5.minutes, 'thing.do')
every(1.hour, 'otherthing.do')

In the first line of this example, an event will be triggered once every five minutes, passing the job name 'thing.do' into the handler. The handler shown above would thus call enqueue_your_job('thing.do').

You can also pass a custom block to the handler, for job queueing systems that rely on classes rather than job names (i.e. DJ and Resque). In this case, you need not define a general event handler, and instead provide one with each event:

every(5.minutes, 'thing.do') { Thing.send_later(:do) }

If you provide a custom handler for the block, the job name is used only for logging.

You can also use blocks to do more complex checks:

every(1.day, 'check.leap.year') do
  Stalker.enqueue('leap.year.party') if Time.now.year % 4 == 0
end

In production

Only one clock process should ever be running across your whole application deployment. For example, if your app is running on three VPS machines (two app servers and one database), your app machines might have the following process topography:

  • App server 1: 3 web (thin start), 3 workers (rake jobs:work), 1 clock (clockwork clock.rb)
  • App server 2: 3 web (thin start), 3 workers (rake jobs:work)

You should use Monit, God, Upstart, or Inittab to keep your clock process running the same way you keep your web and workers running.

Meta

Created by Adam Wiggins

Inspired by rufus-scheduler and http://github.com/bvandenbos/resque-scheduler

Design assistance from Peter van Hardenberg and Matthew Soldo

Patches contributed by Mark McGranaghan and Lukáš Konarovský

Released under the MIT License: http://www.opensource.org/licenses/mit-license.php

http://github.com/adamwiggins/clockwork

clockwork's People

Contributors

adamwiggins avatar lukaskonarovsky avatar mmcgrana avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

clockwork's Issues

Rails Error: Unable to access log file

I have a Rails 3 application which uses delayed_job as job queue. When I use clockwork with the following configuration, I get an error that the rails process can't access the log file.

require File.expand_path('../config/environment', File.dirname(__FILE__))
every(60.seconds, 'check') { Delayed::Job.enqueue(SchedulerJob.new) }
Rails Error: Unable to access log file. Please ensure that  exists and is chmod 0666. The log level has been raised to WARN and the output directed to STDERR until the problem is fixed.

I already checked the permissions of the log file.

Versions used:
Rails 3.0.5
Ruby 1.9.2-p136
delayed_job 2.1.4
clockwork 0.2.3

QUESTION: clockwork will skip execution of the task with the :at option

I read through the docs, it seems conflict between at: and thread:

  • at:
    If another task is already running at the specified time, clockwork will skip execution of the task with the :at option. If this is a problem, please use the :thread option to prevent the long running task from blocking clockwork's scheduler.

  • thread:
    By default, clockwork runs in a single-process and single-thread. If an event handler takes a long time, the main routine of clockwork is blocked until it ends. Clockwork does not misbehave, but the next event is blocked, and runs when the process is returned to the clockwork routine.

I did some tests and I found the task still running after the process is returned to the clockwork routine. So Am I misunderstand some points or the documentation isn't right?

Is it should be If another task is already running at the specified time, clockwork will block execution of the task with the :at option

Memory usage

What's everyone's memory usage running clockwork? On production, I currently have it at 90 MB constantly which is almost as much as my unicorn worker!

How to run clockwork on windows

Hi,

After installing the gem in windows. I tried to run the clockwork command. It gives me below error.

'clockwork' is not recognized as an internal or external command, operable program or batch file.

Kindly help.

Thanks,

Freddy

Numeric clash with ree-1.8.7-2010.02 / Rails 2.3.12

Hi Adam,

When dropping clockwork into our environment (before enabling it, just including the gem) we see some failures in our specs and a hard lock in one of them. When commenting out the Numeric freedom patch, these issues go away.

Doing a timeboxed investigation at the moment, just curious if this rings any bells, thanks!

Rob

Find a non-conflicting name for project

Clockwork is a project that predates this one by two years. Apparently no effort was made to discover if the name was already in use when Adam Wiggins (the author of this project) elected to use it, because Clockwork was published on GitHub and Rubyforge in 2008.

When politely contacted about this name conflict, and the apparent failure to check for existing projects, Adam Wiggins took no responsibility and offhandedly insisted it was my responsibility to rename Clockwork, which pre-dates this project by two years.

This is not good open source citizenship or community membership. Checking for existing projects before publicizing a new one is not an onerous task, it is simple and necessary.

Stop clockwork

How can I stop clockwork, which started by RAILS_ENV=production bundle exec clockwork config/schedule.rb &. We are using it without God, Monit or anything else

Set 'start of the week' day

when I have something like

every(1.week, 'blah')

is there a way for me to specify (or even know) when will it be triggered? Like, Sunday or Monday?

Is there anything I can do to control it?

Configuring exception handling

In my application I would like the exceptions to be sent to bugsnag.
Would you be opened to a contribution that consists in making the error logging configurable?

What happens if there's no queuing?

Hi,

Something the main document doesn't address is what happens if long-run tasks are put directly into clockwork with no queueing. While I understand this isn't recommended, it makes sense in some cases such as when there's no harm if a task gets delayed.

Will clockwork work properly (no exceptions, warnings, errors, ...) if I have it execute a long-lived task that causes another scheduled task to execute later than it would otherwise?

I'd suggest adding the answer to the readme.

Thanks!

-Dan

no activity

I have a load_config initializer with the code below, it does nothing. I can call my TwitterTracker.high manually.

require 'clockwork'
include Clockwork
Rails.logger.info "LOAD"
handler do |job|
Rails.logger.info "JOB ====> #{job}"
TwitterTracker.send(job)
end
every(15.seconds, 'high')
every(5.minutes, 'medium')
every(15.minutes, 'low')

Cannot start with empty clock.rb

If my clock.rb is empty, then attempting to start clockwork gives

.rvm/gems/ruby-1.9.2-p180/gems/clockwork-0.2.4/lib/clockwork.rb:78:in `run': uninitialized class variable @@events in Clockwork (NameError)

Error starting clockwork in production

Trying to run clockwork lib/clock.rb on my production server gives this error:

/mysql_adapter.rb:614:in `real_connect': Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) (Mysql::Error)

From what I can tell, it's trying to connect to the development instance of the database. My production config looks like this:

production:
  adapter: mysql
  encoding: utf8
  *snip*
  socket: /var/run/mysqld/mysqld.sock

I've trying running it via clockwork lib/clock.rb RAILS_ENV=production but that didn't work either.

Rails 3.0.7, on nginx & ubuntu (if that matters)

All events triggered at startup

Let's say I need to run a database cleanup job during a known low period on a weekend, or generate some useful metrics at month-end, what's the best approach to handle that?

The current :at implementation doesn't have the concept of day-of-month or day-of-week ..

datetime wrong

I am in China, I have set timezone to Asia/Shanghai. I employ this project around 09:02.
in mysql table deploy_steps
id deployment_id stage command_id created_at updated_at
158 35 2 NULL 2016-11-30 09:02:59 2016-11-30 09:02:59
159 35 5 NULL 2016-11-30 09:02:59 2016-11-30 09:02:59
160 35 8 NULL 2016-11-30 09:02:59 2016-11-30 09:02:59
161 35 9 1 2016-11-30 09:02:59 2016-11-30 09:02:59
162 35 11 NULL 2016-11-30 09:02:59 2016-11-30 09:02:59
table deploments
id created_at updated_at deleted_at started_at finished_at
35 2016-11-30 09:02:58 2016-11-30 01:03:31 NULL 2016-11-30 01:03:00 2016-11-30 01:03:31
It looks like created_at and uodated_at have different timezone.
and in html it also not match the timezone
deployment/35

Task is not running if previous task in Process

Hi

For example, there are 2 tasks in clock.rb
every(1.week, 'task_1', tz: 'Amsterdam', :at => 'Friday 01:00'){ rake tasks:task_1 }
every(1.week, 'task_2', tz: 'Amsterdam', :at => 'Friday 02:00'){ rake tasks:task_2 }

If task_1 is running till 2:00 then task_2 is not started. Let me know how to start task_2 process when task_1 is already in process.

Thanks

SignalException: SIGTERM

I'm running clockwork on Heroku (Cedar) and I seem to randomly be getting a SignalException: SIGTERM error from clock work.

Here's the backtrace:

vendor/bundle/ruby/1.9.1/gems/clockwork-0.2.4/lib/clockwork.rb:81:in `sleep'
vendor/bundle/ruby/1.9.1/gems/clockwork-0.2.4/lib/clockwork.rb:81:in `block in run'
vendor/bundle/ruby/1.9.1/gems/clockwork-0.2.4/lib/clockwork.rb:79:in `loop'
vendor/bundle/ruby/1.9.1/gems/clockwork-0.2.4/lib/clockwork.rb:79:in `run'
lib/tasks/clockwork.rake:7:in `block (2 levels) in <top (required)>'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/task.rb:205:in `call'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/task.rb:205:in `block in execute'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/task.rb:200:in `each'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/task.rb:200:in `execute'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/task.rb:158:in `block in invoke_with_call_chain'
/usr/local/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/task.rb:151:in `invoke_with_call_chain'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/task.rb:144:in `invoke'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:112:in `invoke_task'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:90:in `block (2 levels) in top_level'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:90:in `each'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:90:in `block in top_level'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:129:in `standard_exception_handling'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:84:in `top_level'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:62:in `block in run'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:129:in `standard_exception_handling'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/lib/rake/application.rb:59:in `run'
vendor/bundle/ruby/1.9.1/gems/rake-0.9.2/bin/rake:32:in `<top (required)>'
vendor/bundle/ruby/1.9.1/bin/rake:19:in `load'
vendor/bundle/ruby/1.9.1/bin/rake:19:in `<main>'

And here's that rake task:

namespace :clockwork do
  desc 'Start the clockwork daemon'
  task :start => :environment do
    Clockwork.every(3.minutes, "numbers.update_all_numbers") {
      Number.delay.update_all_numbers
    }
    Clockwork.run
  end
end

Then in my Procfile I have clock: bundle exec rake clockwork:start

How run command in clockwork

Is it possible to run command in clockwork, like this

ever(1.minute, 'db_backup') {
   command "backup perform --trigger db_backup --config_file config/backup.rb"
 }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.