{"id":25944703,"url":"https://github.com/lambels/cronjob","last_synced_at":"2025-03-04T08:18:49.166Z","repository":{"id":42999023,"uuid":"471115719","full_name":"Lambels/cronjob","owner":"Lambels","description":"Cron but with golang time specification. ⏰","archived":false,"fork":false,"pushed_at":"2022-09-09T16:26:06.000Z","size":35,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-06-20T18:36:24.890Z","etag":null,"topics":["cron","cronjob","daemon","fault-tolerance","go","golang","golang-time","job-scheduling","schedule","scheduler","task-manager"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/Lambels/cronjob@v1.0.0","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Lambels.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2022-03-17T19:28:48.000Z","updated_at":"2023-05-21T17:33:49.000Z","dependencies_parsed_at":"2022-09-08T01:11:17.644Z","dependency_job_id":null,"html_url":"https://github.com/Lambels/cronjob","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lambels%2Fcronjob","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lambels%2Fcronjob/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lambels%2Fcronjob/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lambels%2Fcronjob/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lambels","download_url":"https://codeload.github.com/Lambels/cronjob/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241809577,"owners_count":20023787,"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":["cron","cronjob","daemon","fault-tolerance","go","golang","golang-time","job-scheduling","schedule","scheduler","task-manager"],"created_at":"2025-03-04T08:18:48.353Z","updated_at":"2025-03-04T08:18:49.154Z","avatar_url":"https://github.com/Lambels.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CronJob ![build](https://github.com/Lambels/cronjob/workflows/build/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/Lambels/cronjob)](https://goreportcard.com/report/github.com/Lambels/cronjob)\nCronJob is like cron but uses golang [time](https://pkg.go.dev/time) specification.\n\n### go get it:\n```bash\ngo get github.com/Lambels/cronjob@latest\n```\n\n# Code Examples\n\n## Scheduling functions.\n\nIts very simple, the cronjob object has `AddFunc` method exposed, you use this to add your function to the scheduler.\n`AddFunc` takes 3 parameters respectively: `FuncJob`, `Schedule`, `...JobConf`.\nYou can schedule functions before or after starting the processing thread.\n\n### FuncJob:\n\n`Job1` and `Job2` implement the type `FuncJob`\n\n```go\nfunc Job1() error {\n    fmt.Println(\"Hello World, im a FuncJob\")\n    return nil\n}\n\nfunc Job2() error {\n    fmt.Println(\"Hello World, im also a FuncJob\")\n    return fmt.Errorf(\"ERR\")\n}\n```\n\n### Schedules:\n\nSchedules determine the time at which your `FunJob` runs at.\n\n```go\npackage main\n\nfunc main() {\n    // runs in 5 seconds\n    sched1 := cronjob.In(time.Now(), 5 * time.Second)\n\n    // runs in 1 second\n    sched2 := cronjob.In(time.Now(), 4 * time.Microsecond)\n\n    // runs on 2022, 03, 16 at 16:18:59\n    sched3 := cronjob.At(time.Date(\n        2022,\n        time.March,\n        26,\n        16,\n        18,\n        59,\n        0,\n        time.Local, // use cronjob location.\n    ))\n\n    // runs every hour.\n    sched4 := cronjob.Every(1 * time.Hour)\n\n    // runs on each 3 hour intervals: 03:00, 06:00, 09:00, 12:00, 15:00, 18:00, 21:00, 24:00\n    sched5 := cronjob.EveryFixed(3 * time.Hour)\n}\n```\n\n### JobConf:\n\nJob Configurations configure the behaviour of the job. Examples of such functions are found [here.](https://github.com/Lambels/cronjob/blob/main/conf.go)\n\nA job configuration is a function with the signature `JobConf func(*Job)`.\n\n```go\nfunc Job1() error {\n    fmt.Println(\"Hello World, im a FuncJob\")\n    return nil\n}\n\nfunc Job2() error {\n    fmt.Println(\"Im a FuncJob which returns an error\")\n    return fmt.Errorf(\"ERR\")\n}\n\nfunc main() {\n    cron := cronjob.New()\n\n    cron.AddFunc(\n        Job1,\n        cronjob.In(cron.Now(), 5 * time.Second),\n        \n\n        // configs:\n        cronjob.WithRunOnStart(), // runs job on start.\n    )\n\n    cron.AddFunc(\n        Job2,\n        cronjob.In(cron.Now(), 10 * time.Second),\n\n        // configs:\n        cronjob.WithChain(\n            // retry Job2 5 times in 5 second intervals.\n            // always add cornjob.Retry() the first in the chain.\n            cronjob.NewChain(cronjob.Retry(5 * time.Second, 5)),\n        ),\n    )\n}\n```\n\n### All together:\n\n```go\nfunc Job1() error {\n    fmt.Println(\"Hello World, im a FuncJob\")\n    return nil\n}\n\nfunc Job2() error {\n    fmt.Println(\"Hello World, im also a FuncJob\")\n    return fmt.Errorf(\"ERR\")\n}\n\nfunc main() {\n    cron := cronjob.New()\n\n    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second), cronjob.WithRunOnStart())\n\n    cron.Start()\n\n    cron.AddFunc(Job2, cronjob.EveryFixed(cron.Now(), 1 * time.Hour))\n\n    time.Sleep(1 * time.Hour)\n\n    cron.Close()\n}\n```\n\n## Chains:\n\nChains allow you to customize the behavour of the Jobs when the jobs are running. A chain function making up a chain has the following signature: `func(FuncJob) FuncJob`. A chain is just a slice of these functions: `type Chain []func(FuncJob) FuncJob`.\n\n**cronjob.Retry() should always be added first in the chain to keep expected behaviour.**\n\u003e *Inspiration from [cron](https://github.com/robfig/cron)*\n\n### Creating A Chain:\n```go\nfunc SomeChain(fj cronjob.FuncJob) cronjob.FuncJob {\n\treturn func() error {\n\t\tlog.Println(\"Hello from SomeChain\")\n        return fj() // call next function in chain.\n\t}\n}\n\nfunc SomeOtherChain(fj cronjob.FuncJob) cronjob.FuncJob {\n\treturn func() error {\n\t\tlog.Println(\"Hello from SomeOtherChain\")\n        return fj() // call next function in chain.\n\t}\n}\n\nfunc Job() error {\n    log.Println(\"Hello from Job\")\n    return nil\n}\n\nfunc main() {\n    chain := cronjob.NewChain(SomeChain, SomeOtherChain)\n    chain.Run(job)\n\n    // output:\n    // \"Hello from SomeChain\"\n    // \"Hello from SomeOtherChain\"\n    // \"Hello from Job\"\n}\n```\n\n### Merging n Chains:\n```go\nfunc SomeChain(fj cronjob.FuncJob) cronjob.FuncJob {\n\treturn func() error {\n\t\tlog.Println(\"Hello from SomeChain\")\n        return fj() // call next function in chain.\n\t}\n}\n\nfunc SomeOtherChain(fj cronjob.FuncJob) cronjob.FuncJob {\n\treturn func() error {\n\t\tlog.Println(\"Hello from SomeOtherChain\")\n        return fj() // call next function in chain.\n\t}\n}\n\nfunc SomeOtherOtherChain(fj cronjob.FuncJob) cronjob.FuncJob {\n\treturn func() error {\n\t\tlog.Println(\"Hello from SomeOtherOtherChain\")\n        return fj() // call next function in chain.\n\t}\n}\n\nfunc Job() error {\n    log.Println(\"Hello from Job\")\n    return nil\n}\n\nfunc main() {\n    chain1 := cronjob.NewChain(SomeChain, SomeOtherChain)\n    chain2 := cronjob.NewChain(SomeOtherOtherChain)\n\n    chain3 := cronjob.MergeChains(chain1, chain2)\n    chain3.Run(Job)\n\n    // output:\n    // \"Hello from SomeChain\"\n    // \"Hello from SomeOtherChain\"\n    // \"Hello from SomeOtherOtherChain\"\n    // \"Hello from Job\"\n}\n```\n\n### Fault Tolerance:\n**always add cronjob.Retry() first in the chain!**\n```go\nfunc SomeChain(fj cronjob.FuncJob) cronjob.FuncJob {\n\treturn func() error {\n\t\tlog.Println(\"Hello from SomeChain\")\n        return fj() // call next function in chain.\n\t}\n}\n\nfunc Job() error {\n    log.Println(\"Hello from Job\")\n    return fmt.Errorf(\"ERR\")\n}\n\nfunc main() {\n    chain1 := cronjob.NewChain(cronjob.Retry(5*time.Second, 5), SomeChain)\n\n    chain1.Run(Job)\n\n    // output:\n    // \"Hello from SomeChain\"\n    // \"Hello from Job\"\n    // \"Hello from SomeChain\"\n    // \"Hello from Job\"\n    // \"Hello from SomeChain\"\n    // \"Hello from Job\"\n    // \"Hello from SomeChain\"\n    // \"Hello from Job\"\n    // \"Hello from SomeChain\"\n    // \"Hello from Job\"\n}\n```\n\n## Removing Jobs:\n\nThe cronjob object has `RemoveJob` method exposed, it takes the job id as a parameter. `RemoveJob` will no-op if no job matches the id. You can call `RemoveJob` either after starting the processing thread or before.\n\n### Get Job ID:\n```go\nfunc Job1() error {\n    fmt.Println(\"Hello World, im a FuncJob\")\n    return nil\n}\n\nfunc main() {\n    cron := cronjob.New()\n\n    id := cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))\n\n    // store id ...\n}\n```\n\n### Remove Job:\n```go\nfunc Job1() error {\n    fmt.Println(\"Hello World, im a FuncJob\")\n    return nil\n}\n\nfunc main() {\n    cron := cronjob.New()\n\n    id := cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))\n\n    cron.RemoveJob(id)\n\n    id := cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))\n\n    cron.Start()\n    defer cron.Stop()\n    \n    cron.RemoveJob(id)\n}\n```\n\n## Stopping:\nThere are 2 ways to stop a cronjob's processing thread, `Stop` and `StopWithFlush`. `Stop` exits the processing thread and `StopWithFlush` exits the processing thread and runs the remaining jobs providing a context to wait for their completion.\n\n### Stop:\n```go\nfunc Job1() error {\n    fmt.Println(\"Hello World, im a FuncJob\")\n    return nil\n}\n\nfunc main() {\n    cron := cronjob.New()\n\n    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))\n\n    cron.Start()\n    cron.Stop()\n\n    cron.AddFunc(Job1, cronjob.In(cron.Now(), 2 * time.Second)) // still works.\n}\n```\n\n### StopWithFlush:\n```go\nfunc Job1() error {\n    time.Sleep(1 * time.Hour)\n    return nil\n}\nfunc Job2() error {\n    time.Sleep(5 * time.Second)\n    return nil\n}\n\nfunc main() {\n    cron := cronjob.New()\n\n    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))\n    cron.AddFunc(Job1, cronjob.In(cron.Now(), 5 * time.Second))\n\n    cron.Start()\n    ctx := cron.StopWithFlush()\n    \u003c-ctx.Done() // waits for Job1 and Job2 to finish. (1 hour)\n\n    cron.AddFunc(Job1, cronjob.In(cron.Now(), 2 * time.Second)) // still works.\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambels%2Fcronjob","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flambels%2Fcronjob","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambels%2Fcronjob/lists"}