{"id":13879921,"url":"https://github.com/treasure-data/perfectsched","last_synced_at":"2025-04-23T13:53:24.810Z","repository":{"id":677657,"uuid":"2290183","full_name":"treasure-data/perfectsched","owner":"treasure-data","description":"Highly available distributed cron built on RDBMS","archived":false,"fork":false,"pushed_at":"2022-10-04T14:24:45.000Z","size":149,"stargazers_count":97,"open_issues_count":1,"forks_count":14,"subscribers_count":85,"default_branch":"master","last_synced_at":"2025-03-20T20:11:01.420Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/treasure-data.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-08-29T18:14:23.000Z","updated_at":"2023-10-24T18:47:11.000Z","dependencies_parsed_at":"2022-08-16T10:40:27.481Z","dependency_job_id":null,"html_url":"https://github.com/treasure-data/perfectsched","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treasure-data%2Fperfectsched","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treasure-data%2Fperfectsched/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treasure-data%2Fperfectsched/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treasure-data%2Fperfectsched/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/treasure-data","download_url":"https://codeload.github.com/treasure-data/perfectsched/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250000868,"owners_count":21358817,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-06T08:02:39.166Z","updated_at":"2025-04-23T13:53:24.793Z","avatar_url":"https://github.com/treasure-data.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# PerfectSched\n\n[![Build Status](https://travis-ci.org/treasure-data/perfectsched.svg?branch=master)](https://travis-ci.org/treasure-data/perfectsched)\n[![Coverage Status](https://coveralls.io/repos/treasure-data/perfectsched/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/treasure-data/perfectsched?branch=master)\n\nPerfectSched is a highly available distributed cron built on top of RDBMS.\n\nIt provides at-least-once semantics; Even if a worker node fails during process a task, the task is retried by another worker.\n\nPerfectSched also guarantees that only one worker server processes a task if the server is alive.\n\nAll you have to consider is implementing idempotent worker programs. It's recommended to use [PerfectQueue](https://github.com/treasure-data/perfectqueue) with PerfectSched.\n\n\n## API overview\n\n```\n# open a schedule collection\nPerfectSched.open(config, \u0026block)  #=\u003e #\u003cScheduleCollection\u003e\n\n# add a schedule\nScheduleCollection#add(task_id, type, options)\n\n# poll a scheduled task\n# (you don't have to use this method directly. see following sections)\nScheduleCollection#poll  #=\u003e #\u003cTask\u003e\n\n# get data associated with a task\nTask#data  #=\u003e #\u003cHash\u003e\n\n# finish a task\nTask#finish!\n\n# retry a task\nTask#retry!\n\n# create a schedule reference\nScheduleCollection#[](key)  #=\u003e #\u003cSchedule\u003e\n\n# chack the existance of the schedule\nSchedule#exists?\n\n# delete a schedule\nSchedule#delete!\n```\n\n### Error classes\n\n```\nScheduleError \u003c StandardError\n\n##\n# Workers may get these errors:\n#\n\nAlreadyFinishedError \u003c ScheduleError\n\nNotFoundError \u003c ScheduleError\n\nPreemptedError \u003c ScheduleError\n\nProcessStopError \u003c RuntimeError\n\n##\n# Client or other situation:\n#\n\nConfigError \u003c RuntimeError\n\nAlreadyExistsError \u003c ScheduleError\n\nNotSupportedError \u003c ScheduleError\n```\n\n\n### Example\n\n```ruby\n# submit a task\nPerfectSched.open(config) {|sc|\n  data = {'key'=\u003e\"value\"}\n  options = {\n    :cron =\u003e '0 * * * *',\n    :delay =\u003e 30,\n    :timezone =\u003e 'Asia/Tokyo',\n    :next_time =\u003e Time.parse('2013-01-01 00:00:00 +0900').to_i,\n    :data =\u003e data,\n  }\n  sc.add(\"sched-id\", \"type1\", options)\n}\n```\n\n\n## Writing a worker application\n\n### 1. Implement PerfectSched::Application::Base\n\n```ruby\nclass TestHandler \u003c PerfectSched::Application::Base\n  # implement run method\n  def run\n    # do something ...\n    puts \"acquired task: #{task.inspect}\"\n\n    # call task.finish!, task.retry! or task.release!\n    task.finish!\n  end\nend\n```\n\n### 2. Implement PerfectSched::Application::Dispatch\n\n```ruby\nclass Dispatch \u003c PerfectSched::Application::Dispatch\n  # describe routing\n  route \"type1\" =\u003e TestHandler\n  route /^regexp-.*$/ =\u003e :TestHandler  # String or Regexp =\u003e Class or Symbol\nend\n```\n\n### 3. Run the worker\n\nIn a launcher script or rake file:\n\n```ruby\nsystem('perfectsched run -I. -rapp/schedules/dispatch Dispatch')\n```\n\nor:\n\n```ruby\nrequire 'perfectsched'\nrequire 'app/schedules/dispatch'\n\nPerfectSched::Worker.run(Dispatch) {\n  # this method is called when the worker process is restarted\n  raw = File.read('config/perfectsched.yml')\n  yml = YAJL.load(raw)\n  yml[ENV['RAILS_ENV'] || 'development']\n}\n```\n\n### Signal handlers\n\n- **TERM**,**INT**,**QUIT:** shutdown\n- **USR1**,**HUP:** restart\n- **USR2:** reopen log files\n\n## Configuration\n\n- **type:** backend type (required; see following sections)\n- **log:** log file path (default: use stderr)\n- **poll\\_interval:** interval to poll tasks in seconds (default: 1.0 sec)\n- **timezone:** default timezone (default: 'UTC')\n- **alive\\_time:** duration to continue a heartbeat request (default: 300 sec)\n- **retry\\_wait:** duration to retry a retried task (default: 300 sec)\n\n## Backend types\n\n### rdb\\_compat\n\nadditional configuration:\n\n- **url:** URL to the RDBMS (example: 'mysql://user:password@host:port/database')\n- **table:** name of the table to use\n\n### rdb\n\nNot implemented yet.\n\n\n## Command line management tool\n\n```\nUsage: perfectsched [options] \u003ccommand\u003e\n\ncommands:\n    list                             Show list of registered schedules\n    add \u003ckey\u003e \u003ctype\u003e \u003ccron\u003e \u003cdata\u003e   Register a new schedule\n    delete \u003ckey\u003e                     Delete a registered schedule\n    run \u003cclass\u003e                      Run a worker process\n    init                             Initialize a backend database\n\noptions:\n    -e, --environment ENV            Framework environment (default: development)\n    -c, --config PATH.yml            Path to a configuration file (default: config/perfectsched.yml)\n\noptions for add:\n    -d, --delay SEC                  Delay time before running a schedule (default: 0)\n    -t, --timezone NAME              Set timezone (default: UTC)\n    -s, --start UNIXTIME             Set the first schedule time (default: now)\n    -a, --at UNIXTIME                Set the first run time (default: start+delay)\n\noptions for run:\n    -I, --include PATH               Add $LOAD_PATH directory\n    -r, --require PATH               Require files before starting\n```\n\n### initializing a database\n\n    # assume that the config/perfectsched.yml exists\n    $ perfectsched init\n\n### submitting a task\n\n    $ perfectsched add s1 user_task '* * * * *' '{}'\n\n### listing tasks\n\n    $ perfectsched list\n                               key            type               cron   delay    timezone                    next_time                next_run_time  data\n                                s1       user_task          * * * * *       0         UTC      2012-05-18 22:04:00 UTC      2012-05-18 22:04:00 UTC  {}\n    1 entries.\n\n### delete a schedule\n\n    $ perfectsched delete s1\n\n### running a worker\n\n    $ perfectsched run -I. -Ilib -rconfig/boot.rb -rapps/schedules/schedule_dispatch.rb ScheduleDispatch\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreasure-data%2Fperfectsched","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftreasure-data%2Fperfectsched","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreasure-data%2Fperfectsched/lists"}