{"id":28380695,"url":"https://github.com/0xsequence/runnable","last_synced_at":"2025-06-24T21:31:31.281Z","repository":{"id":236034654,"uuid":"791767236","full_name":"0xsequence/runnable","owner":"0xsequence","description":null,"archived":false,"fork":false,"pushed_at":"2024-11-28T13:33:14.000Z","size":14,"stargazers_count":4,"open_issues_count":2,"forks_count":1,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-06-06T03:40:43.135Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/0xsequence.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-25T10:28:53.000Z","updated_at":"2024-11-28T13:32:31.000Z","dependencies_parsed_at":"2024-06-19T11:25:43.437Z","dependency_job_id":"61e06105-320d-4caa-9e78-649960bd3c3b","html_url":"https://github.com/0xsequence/runnable","commit_stats":null,"previous_names":["0xsequence/runnable"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/0xsequence/runnable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xsequence%2Frunnable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xsequence%2Frunnable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xsequence%2Frunnable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xsequence%2Frunnable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0xsequence","download_url":"https://codeload.github.com/0xsequence/runnable/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0xsequence%2Frunnable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261759119,"owners_count":23205498,"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":"2025-05-30T03:09:03.862Z","updated_at":"2025-06-24T21:31:31.273Z","avatar_url":"https://github.com/0xsequence.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# runnable\n\n![Build \u0026 Unit Tests](https://github.com/0xsequence/runnable/actions/workflows/go.yml/badge.svg)\n\n\n## Overview\n\n`runnable` is a Go package that provides a `Runnable` interface for functions or objects that can be started and stopped.\nIt provides a simple way to run a function or object in a goroutine and stop it when needed. It also provides a way to run a\nfunction with retry and statistics number of restarts, when started and stopped, if returned error, etc.\n\n## Examples\n\n### Runnable Function\n```go\nfmt.Println(\"Simple function...\")\nerr := runnable.New(func(ctx context.Context) error {\n    fmt.Println(\"Starting...\")\n    defer fmt.Println(\"Stopping...\")\n\n    for i := 0; i \u003c 5; i++ {\n        select {\n        case \u003c-ctx.Done():\n            return nil\n        default:\n        }\n        time.Sleep(1 * time.Second)\n        fmt.Println(\"Running...\")\n    }\n    return nil\n}).Run(context.Background())\nif err != nil {\n    fmt.Println(err)\n}\n```\n\n### Runnable Function with Stop\n```go\nfmt.Println(\"Simple function with stop...\")\nr := runnable.New(func(ctx context.Context) error {\n    fmt.Println(\"Starting...\")\n    defer fmt.Println(\"Stopping...\")\n\n    for {\n        select {\n        case \u003c-ctx.Done():\n            return nil\n        default:\n        }\n        time.Sleep(1 * time.Second)\n        fmt.Println(\"Running...\")\n    }\n})\n\ngo func() {\n    time.Sleep(5 * time.Second)\n\n    fmt.Println(\"Calling Stop...\")\n    err := r.Stop(context.Background())\n    if err != nil {\n        fmt.Println(err)\n    }\n}()\n\nerr = r.Run(context.Background())\nif err != nil {\n    fmt.Println(err)\n}\n```\n\n### Runnable Function with timeout\n```go\nfmt.Println(\"Simple function with timeout...\")\nctxWithTimeout, _ := context.WithTimeout(context.Background(), 5*time.Second)\nerr = runnable.New(func(ctx context.Context) error {\n    fmt.Println(\"Starting...\")\n    defer fmt.Println(\"Stopping...\")\n\n    for {\n        select {\n        case \u003c-ctx.Done():\n            return nil\n        default:\n        }\n        time.Sleep(1 * time.Second)\n        fmt.Println(\"Running...\")\n    }\n}).Run(ctxWithTimeout)\nif err != nil {\n    fmt.Println(err)\n}\n```\n\n### Runnable Function with retry\n```go\nfmt.Println(\"Simple function with retry...\")\nerrorReturned := false\nerr = runnable.New(func(ctx context.Context) error {\n    fmt.Println(\"Starting...\")\n    defer fmt.Println(\"Stopping...\")\n    \n    if !errorReturned {\n        errorReturned = true\n        return fmt.Errorf(\"error\")\n    }\n    \n    // do something\n    for i := 0; i \u003c 5; i++ {\n        select {\n        case \u003c-ctx.Done():\n            return nil\n        default:\n        }\n        time.Sleep(1 * time.Second)\n        fmt.Println(\"Running...\")\n    }\n    return nil\n}, runnable.WithRetry(3, runnable.ResetNever)).Run(context.Background())\nif err != nil {\n    fmt.Println(err)\n}\n```\n\n### Runnable Object\n```go\npackage main\n\nimport (\n\t\"time\"\n\n\t\"github.com/0xsequence/runnable\"\n)\n\ntype Monitor struct {\n\trunnable.Runnable\n}\n\nfunc NewMonitor() *Monitor {\n\tm := \u0026Monitor{}\n\tm.Runnable = runnable.New(m.run)\n\treturn m\n}\n\nfunc (m *Monitor) run(ctx context.Context) error {\n\tfmt.Println(\"Starting...\")\n\tdefer fmt.Println(\"Stopping...\")\n\t\n\t// Start monitoring\n\tfor {\n\t\tselect {\n\t\tcase \u003c-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\n\t\ttime.Sleep(1 * time.Second)\n\t\tfmt.Println(\"Monitoring...\")\n\t}\n\treturn nil\n}\n\nfunc main() {\n\tfmt.Println(\"Runnable object(Monitor)...\")\n\tm := NewMonitor()\n\n\tgo func() {\n\t\ttime.Sleep(5 * time.Second)\n\n\t\tfmt.Println(\"Calling Stop...\")\n\t\terr := m.Stop(context.Background())\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t}\n\t}()\n\n\terr = m.Run(context.Background())\n\tif err != nil {\n\t\tfmt.Println(err)\n\t}\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xsequence%2Frunnable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0xsequence%2Frunnable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0xsequence%2Frunnable/lists"}