{"action":"created","comment":{"url":"https://api.github.com/repos/cozy/cozy-stack/pulls/comments/91630403","pull_request_review_id":12140196,"id":91630403,"diff_hunk":"@@ -0,0 +1,432 @@\n+Cozy Jobs\n+=========\n+\n+Jobs are designed to represent asynchronous tasks that your cozy can execute. These tasks can be scheduled in advance, recurring or suddenn and provide various services.\n+\n+At the time, we do not provide \"generic\" and programmable tasks. This list of available workers is part of the defined API.\n+\n+The job queue can be either local the cozy-stack when used as a monolitic instance (self-hosted for instance) or distributed via a redis server for distributed infrastructures.\n+\n+This doc introduces two cozy types:\n+\n+  - `io.cozy.jobs` for jobs\n+  - `io.cozy.launchers` for launchers\n+\n+\n+Launchers\n+---------\n+\n+Jobs can be launched by three types of launchers:\n+\n+  - `@cron` to schedule recurring jobs, either periodic or scheduled at specific times\n+  - `@interval` to schedule jobs executed at a given fix interval\n+  - `@event` to launch a job after a change in the cozy\n+\n+These three launchers have specific syntaxes to describe when jobs should be scheduled. See below for more informations.\n+\n+Jobs can also be queued up programatically, without the help of a specific launcher directly via the `/jobs/queue` API. In this case the `launcher` name is empty.\n+\n+### `@cron` syntax\n+\n+In order to schedule recurring jobs, the `cron` launcher has the syntax using six fields:\n+\n+```\n+Field name   | Mandatory? | Allowed values  | Allowed special characters\n+----------   | ---------- | --------------  | --------------------------\n+Seconds      | Yes        | 0-59            | * / , -\n+Minutes      | Yes        | 0-59            | * / , -\n+Hours        | Yes        | 0-23            | * / , -\n+Day of month | Yes        | 1-31            | * / , - ?\n+Month        | Yes        | 1-12 or JAN-DEC | * / , -\n+Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?\n+------------------------------------------------------------------------\n+\n+Asterisk ( * )\n+\n+The asterisk indicates that the cron expression will match for all values of\n+the field; e.g., using an asterisk in the 5th field (month) would indicate\n+every month.\n+\n+Slash ( / )\n+\n+Slashes are used to describe increments of ranges. For example 3-59/15 in the\n+1st field (minutes) would indicate the 3rd minute of the hour and every 15\n+minutes thereafter. The form \"*\\/...\" is equivalent to the form \"first-\n+last/...\", that is, an increment over the largest possible range of the field.\n+The form \"N/...\" is accepted as meaning \"N-MAX/...\", that is, starting at N,\n+use the increment until the end of that specific range. It does not wrap\n+around.\n+\n+Comma ( , )\n+\n+Commas are used to separate items of a list. For example, using \"MON,WED,FRI\"\n+in the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.\n+\n+Hyphen ( - )\n+\n+Hyphens are used to define ranges. For example, 9-17 would indicate every hour\n+between 9am and 5pm inclusive.\n+\n+Question mark ( ? )\n+\n+Question mark may be used instead of '*' for leaving either day-of-month or\n+day-of-week blank.\n+```\n+\n+To schedule jobs given an interval:\n+\n+Examples:\n+\n+```\n+@cron 0 0 0 1 1 * # Run once a year, midnight, Jan. 1st\n+@cron 0 0 0 1 1 * # Run once a year, midnight, Jan. 1st\n+@cron 0 0 0 1 * * # Run once a month, midnight, first of month\n+@cron 0 0 0 * * 0 # Run once a week, midnight on Sunday\n+@cron 0 0 0 * * * # Run once a day, midnight\n+@cron 0 0 * * * * # Run once an hour, beginning of hour\n+```\n+\n+\n+### `@interval` syntax\n+\n+The `@interval` launcher uses the same syntax as golang's `time.ParseDuration`:\n+\n+```\n+A duration string is a possibly signed sequence of decimal numbers, each with\n+optional fraction and a unit suffix, such as \"300ms\", \"1.5h\" or \"2h45m\". Valid\n+time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".\n+```\n+\n+Examples\n+\n+```\n+@interval 1.5h   # schedules every 1 and a half hours\n+@interval 30m10s # schedules every 30 minutes and 10 seconds\n+```\n+\n+\n+### `@event` syntax\n+\n+The `@event` syntax is not determined yet. Its main purpose will be to describe job scheduling after a filesystem or database modification.\n+\n+\n+### Launcher rate limitation\n+\n+Every launcher has a rate limitation policy to prevent launchers from spawning too many jobs at the same time. The specific rules are not yet decided, but they should work along these two properties:\n+\n+  - *parallel limitations*: each launcher will have a limited number of workers it is allowed to queue in parallel\n+  - *back pressure*: each launcher should have a backpressure policy to drop job spawning when not necessary. For instance: ","path":"docs/jobs.md","position":118,"original_position":118,"commit_id":"d07dc030b514bfbeea18f3a0588e5d5ce416db6b","original_commit_id":"d07dc030b514bfbeea18f3a0588e5d5ce416db6b","user":{"login":"aenario","id":1580287,"avatar_url":"https://avatars.githubusercontent.com/u/1580287?v=3","gravatar_id":"","url":"https://api.github.com/users/aenario","html_url":"https://github.com/aenario","followers_url":"https://api.github.com/users/aenario/followers","following_url":"https://api.github.com/users/aenario/following{/other_user}","gists_url":"https://api.github.com/users/aenario/gists{/gist_id}","starred_url":"https://api.github.com/users/aenario/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aenario/subscriptions","organizations_url":"https://api.github.com/users/aenario/orgs","repos_url":"https://api.github.com/users/aenario/repos","events_url":"https://api.github.com/users/aenario/events{/privacy}","received_events_url":"https://api.github.com/users/aenario/received_events","type":"User","site_admin":false},"body":"This also brings the idea of leading / trailing debounce with `@event`\r\nie. a job that do some action after any contact update, but should only be triggered once after several contacts are updated.","created_at":"2016-12-08T23:22:42Z","updated_at":"2016-12-08T23:26:57Z","html_url":"https://github.com/cozy/cozy-stack/pull/140#discussion_r91630403","pull_request_url":"https://api.github.com/repos/cozy/cozy-stack/pulls/140","_links":{"self":{"href":"https://api.github.com/repos/cozy/cozy-stack/pulls/comments/91630403"},"html":{"href":"https://github.com/cozy/cozy-stack/pull/140#discussion_r91630403"},"pull_request":{"href":"https://api.github.com/repos/cozy/cozy-stack/pulls/140"}}},"pull_request":{"url":"https://api.github.com/repos/cozy/cozy-stack/pulls/140","id":97159956,"html_url":"https://github.com/cozy/cozy-stack/pull/140","diff_url":"https://github.com/cozy/cozy-stack/pull/140.diff","patch_url":"https://github.com/cozy/cozy-stack/pull/140.patch","issue_url":"https://api.github.com/repos/cozy/cozy-stack/issues/140","number":140,"state":"open","locked":false,"title":"Add jobs doc","user":{"login":"jinroh","id":687847,"avatar_url":"https://avatars.githubusercontent.com/u/687847?v=3","gravatar_id":"","url":"https://api.github.com/users/jinroh","html_url":"https://github.com/jinroh","followers_url":"https://api.github.com/users/jinroh/followers","following_url":"https://api.github.com/users/jinroh/following{/other_user}","gists_url":"https://api.github.com/users/jinroh/gists{/gist_id}","starred_url":"https://api.github.com/users/jinroh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jinroh/subscriptions","organizations_url":"https://api.github.com/users/jinroh/orgs","repos_url":"https://api.github.com/users/jinroh/repos","events_url":"https://api.github.com/users/jinroh/events{/privacy}","received_events_url":"https://api.github.com/users/jinroh/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-12-08T16:55:41Z","updated_at":"2016-12-08T23:26:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"510a8fda9c937e5965c5c65aadd4bc5e9e0654bd","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/cozy/cozy-stack/pulls/140/commits","review_comments_url":"https://api.github.com/repos/cozy/cozy-stack/pulls/140/comments","review_comment_url":"https://api.github.com/repos/cozy/cozy-stack/pulls/comments{/number}","comments_url":"https://api.github.com/repos/cozy/cozy-stack/issues/140/comments","statuses_url":"https://api.github.com/repos/cozy/cozy-stack/statuses/d07dc030b514bfbeea18f3a0588e5d5ce416db6b","head":{"label":"jinroh:jobs","ref":"jobs","sha":"d07dc030b514bfbeea18f3a0588e5d5ce416db6b","user":{"login":"jinroh","id":687847,"avatar_url":"https://avatars.githubusercontent.com/u/687847?v=3","gravatar_id":"","url":"https://api.github.com/users/jinroh","html_url":"https://github.com/jinroh","followers_url":"https://api.github.com/users/jinroh/followers","following_url":"https://api.github.com/users/jinroh/following{/other_user}","gists_url":"https://api.github.com/users/jinroh/gists{/gist_id}","starred_url":"https://api.github.com/users/jinroh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jinroh/subscriptions","organizations_url":"https://api.github.com/users/jinroh/orgs","repos_url":"https://api.github.com/users/jinroh/repos","events_url":"https://api.github.com/users/jinroh/events{/privacy}","received_events_url":"https://api.github.com/users/jinroh/received_events","type":"User","site_admin":false},"repo":{"id":70130658,"name":"cozy-stack","full_name":"jinroh/cozy-stack","owner":{"login":"jinroh","id":687847,"avatar_url":"https://avatars.githubusercontent.com/u/687847?v=3","gravatar_id":"","url":"https://api.github.com/users/jinroh","html_url":"https://github.com/jinroh","followers_url":"https://api.github.com/users/jinroh/followers","following_url":"https://api.github.com/users/jinroh/following{/other_user}","gists_url":"https://api.github.com/users/jinroh/gists{/gist_id}","starred_url":"https://api.github.com/users/jinroh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jinroh/subscriptions","organizations_url":"https://api.github.com/users/jinroh/orgs","repos_url":"https://api.github.com/users/jinroh/repos","events_url":"https://api.github.com/users/jinroh/events{/privacy}","received_events_url":"https://api.github.com/users/jinroh/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jinroh/cozy-stack","description":"Simple, Versatile, Yours","fork":true,"url":"https://api.github.com/repos/jinroh/cozy-stack","forks_url":"https://api.github.com/repos/jinroh/cozy-stack/forks","keys_url":"https://api.github.com/repos/jinroh/cozy-stack/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jinroh/cozy-stack/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jinroh/cozy-stack/teams","hooks_url":"https://api.github.com/repos/jinroh/cozy-stack/hooks","issue_events_url":"https://api.github.com/repos/jinroh/cozy-stack/issues/events{/number}","events_url":"https://api.github.com/repos/jinroh/cozy-stack/events","assignees_url":"https://api.github.com/repos/jinroh/cozy-stack/assignees{/user}","branches_url":"https://api.github.com/repos/jinroh/cozy-stack/branches{/branch}","tags_url":"https://api.github.com/repos/jinroh/cozy-stack/tags","blobs_url":"https://api.github.com/repos/jinroh/cozy-stack/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jinroh/cozy-stack/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jinroh/cozy-stack/git/refs{/sha}","trees_url":"https://api.github.com/repos/jinroh/cozy-stack/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jinroh/cozy-stack/statuses/{sha}","languages_url":"https://api.github.com/repos/jinroh/cozy-stack/languages","stargazers_url":"https://api.github.com/repos/jinroh/cozy-stack/stargazers","contributors_url":"https://api.github.com/repos/jinroh/cozy-stack/contributors","subscribers_url":"https://api.github.com/repos/jinroh/cozy-stack/subscribers","subscription_url":"https://api.github.com/repos/jinroh/cozy-stack/subscription","commits_url":"https://api.github.com/repos/jinroh/cozy-stack/commits{/sha}","git_commits_url":"https://api.github.com/repos/jinroh/cozy-stack/git/commits{/sha}","comments_url":"https://api.github.com/repos/jinroh/cozy-stack/comments{/number}","issue_comment_url":"https://api.github.com/repos/jinroh/cozy-stack/issues/comments{/number}","contents_url":"https://api.github.com/repos/jinroh/cozy-stack/contents/{+path}","compare_url":"https://api.github.com/repos/jinroh/cozy-stack/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jinroh/cozy-stack/merges","archive_url":"https://api.github.com/repos/jinroh/cozy-stack/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jinroh/cozy-stack/downloads","issues_url":"https://api.github.com/repos/jinroh/cozy-stack/issues{/number}","pulls_url":"https://api.github.com/repos/jinroh/cozy-stack/pulls{/number}","milestones_url":"https://api.github.com/repos/jinroh/cozy-stack/milestones{/number}","notifications_url":"https://api.github.com/repos/jinroh/cozy-stack/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jinroh/cozy-stack/labels{/name}","releases_url":"https://api.github.com/repos/jinroh/cozy-stack/releases{/id}","deployments_url":"https://api.github.com/repos/jinroh/cozy-stack/deployments","created_at":"2016-10-06T07:03:29Z","updated_at":"2016-10-06T07:03:30Z","pushed_at":"2016-12-08T17:04:22Z","git_url":"git://github.com/jinroh/cozy-stack.git","ssh_url":"git@github.com:jinroh/cozy-stack.git","clone_url":"https://github.com/jinroh/cozy-stack.git","svn_url":"https://github.com/jinroh/cozy-stack","homepage":"https://cozy.io","size":901,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"cozy:master","ref":"master","sha":"d243b5595e491684310829db29fbb2d2c9dafa71","user":{"login":"cozy","id":7690525,"avatar_url":"https://avatars.githubusercontent.com/u/7690525?v=3","gravatar_id":"","url":"https://api.github.com/users/cozy","html_url":"https://github.com/cozy","followers_url":"https://api.github.com/users/cozy/followers","following_url":"https://api.github.com/users/cozy/following{/other_user}","gists_url":"https://api.github.com/users/cozy/gists{/gist_id}","starred_url":"https://api.github.com/users/cozy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cozy/subscriptions","organizations_url":"https://api.github.com/users/cozy/orgs","repos_url":"https://api.github.com/users/cozy/repos","events_url":"https://api.github.com/users/cozy/events{/privacy}","received_events_url":"https://api.github.com/users/cozy/received_events","type":"Organization","site_admin":false},"repo":{"id":63433838,"name":"cozy-stack","full_name":"cozy/cozy-stack","owner":{"login":"cozy","id":7690525,"avatar_url":"https://avatars.githubusercontent.com/u/7690525?v=3","gravatar_id":"","url":"https://api.github.com/users/cozy","html_url":"https://github.com/cozy","followers_url":"https://api.github.com/users/cozy/followers","following_url":"https://api.github.com/users/cozy/following{/other_user}","gists_url":"https://api.github.com/users/cozy/gists{/gist_id}","starred_url":"https://api.github.com/users/cozy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cozy/subscriptions","organizations_url":"https://api.github.com/users/cozy/orgs","repos_url":"https://api.github.com/users/cozy/repos","events_url":"https://api.github.com/users/cozy/events{/privacy}","received_events_url":"https://api.github.com/users/cozy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/cozy/cozy-stack","description":"Simple, Versatile, Yours","fork":false,"url":"https://api.github.com/repos/cozy/cozy-stack","forks_url":"https://api.github.com/repos/cozy/cozy-stack/forks","keys_url":"https://api.github.com/repos/cozy/cozy-stack/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cozy/cozy-stack/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cozy/cozy-stack/teams","hooks_url":"https://api.github.com/repos/cozy/cozy-stack/hooks","issue_events_url":"https://api.github.com/repos/cozy/cozy-stack/issues/events{/number}","events_url":"https://api.github.com/repos/cozy/cozy-stack/events","assignees_url":"https://api.github.com/repos/cozy/cozy-stack/assignees{/user}","branches_url":"https://api.github.com/repos/cozy/cozy-stack/branches{/branch}","tags_url":"https://api.github.com/repos/cozy/cozy-stack/tags","blobs_url":"https://api.github.com/repos/cozy/cozy-stack/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cozy/cozy-stack/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cozy/cozy-stack/git/refs{/sha}","trees_url":"https://api.github.com/repos/cozy/cozy-stack/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cozy/cozy-stack/statuses/{sha}","languages_url":"https://api.github.com/repos/cozy/cozy-stack/languages","stargazers_url":"https://api.github.com/repos/cozy/cozy-stack/stargazers","contributors_url":"https://api.github.com/repos/cozy/cozy-stack/contributors","subscribers_url":"https://api.github.com/repos/cozy/cozy-stack/subscribers","subscription_url":"https://api.github.com/repos/cozy/cozy-stack/subscription","commits_url":"https://api.github.com/repos/cozy/cozy-stack/commits{/sha}","git_commits_url":"https://api.github.com/repos/cozy/cozy-stack/git/commits{/sha}","comments_url":"https://api.github.com/repos/cozy/cozy-stack/comments{/number}","issue_comment_url":"https://api.github.com/repos/cozy/cozy-stack/issues/comments{/number}","contents_url":"https://api.github.com/repos/cozy/cozy-stack/contents/{+path}","compare_url":"https://api.github.com/repos/cozy/cozy-stack/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cozy/cozy-stack/merges","archive_url":"https://api.github.com/repos/cozy/cozy-stack/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cozy/cozy-stack/downloads","issues_url":"https://api.github.com/repos/cozy/cozy-stack/issues{/number}","pulls_url":"https://api.github.com/repos/cozy/cozy-stack/pulls{/number}","milestones_url":"https://api.github.com/repos/cozy/cozy-stack/milestones{/number}","notifications_url":"https://api.github.com/repos/cozy/cozy-stack/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cozy/cozy-stack/labels{/name}","releases_url":"https://api.github.com/repos/cozy/cozy-stack/releases{/id}","deployments_url":"https://api.github.com/repos/cozy/cozy-stack/deployments","created_at":"2016-07-15T15:54:30Z","updated_at":"2016-12-06T13:34:40Z","pushed_at":"2016-12-08T17:04:23Z","git_url":"git://github.com/cozy/cozy-stack.git","ssh_url":"git@github.com:cozy/cozy-stack.git","clone_url":"https://github.com/cozy/cozy-stack.git","svn_url":"https://github.com/cozy/cozy-stack","homepage":"https://cozy.io","size":940,"stargazers_count":33,"watchers_count":33,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":14,"mirror_url":null,"open_issues_count":4,"forks":14,"open_issues":4,"watchers":33,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/cozy/cozy-stack/pulls/140"},"html":{"href":"https://github.com/cozy/cozy-stack/pull/140"},"issue":{"href":"https://api.github.com/repos/cozy/cozy-stack/issues/140"},"comments":{"href":"https://api.github.com/repos/cozy/cozy-stack/issues/140/comments"},"review_comments":{"href":"https://api.github.com/repos/cozy/cozy-stack/pulls/140/comments"},"review_comment":{"href":"https://api.github.com/repos/cozy/cozy-stack/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/cozy/cozy-stack/pulls/140/commits"},"statuses":{"href":"https://api.github.com/repos/cozy/cozy-stack/statuses/d07dc030b514bfbeea18f3a0588e5d5ce416db6b"}}}}
{"actor":{"display_login":"aenario"}}