{"id":18447170,"url":"https://github.com/roadrunner-server/endure","last_synced_at":"2025-12-16T01:02:23.086Z","repository":{"id":37371761,"uuid":"226337444","full_name":"roadrunner-server/endure","owner":"roadrunner-server","description":"⚡  Fault-tolerant service container for creating plugins","archived":false,"fork":false,"pushed_at":"2024-08-27T09:43:51.000Z","size":1204,"stargazers_count":71,"open_issues_count":0,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-08-27T10:48:26.708Z","etag":null,"topics":["golang","graph","plugin-manager"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"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/roadrunner-server.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"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},"funding":{"github":"roadrunner-server"}},"created_at":"2019-12-06T13:35:45.000Z","updated_at":"2024-08-27T09:43:55.000Z","dependencies_parsed_at":"2024-02-11T16:46:40.052Z","dependency_job_id":"a3877176-9606-40a0-8f31-52ce68d80e9e","html_url":"https://github.com/roadrunner-server/endure","commit_stats":{"total_commits":566,"total_committers":5,"mean_commits":113.2,"dds":"0.45759717314487636","last_synced_commit":"02d7980782a9abab8648b6d7cb18f5de62008563"},"previous_names":["spiral/endure","spiral/cascade"],"tags_count":68,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadrunner-server%2Fendure","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadrunner-server%2Fendure/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadrunner-server%2Fendure/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roadrunner-server%2Fendure/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/roadrunner-server","download_url":"https://codeload.github.com/roadrunner-server/endure/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240275922,"owners_count":19775616,"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":["golang","graph","plugin-manager"],"created_at":"2024-11-06T07:12:12.192Z","updated_at":"2025-12-16T01:02:23.032Z","avatar_url":"https://github.com/roadrunner-server.png","language":"Go","readme":"# Endure\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://roadrunner.dev\" target=\"_blank\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/roadrunner-server/.github/assets/8040338/e6bde856-4ec6-4a52-bd5b-bfe78736c1ff\"\u003e\n    \u003cimg align=\"center\" src=\"https://github.com/roadrunner-server/.github/assets/8040338/040fb694-1dd3-4865-9d29-8e0748c2c8b8\"\u003e\n  \u003c/picture\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n \u003ca href=\"https://pkg.go.dev/github.com/roadrunner-server/endure/v2?tab=doc\"\u003e\u003cimg src=\"https://godoc.org/github.com/roadrunner-server/endure/v2?status.svg\"\u003e\u003c/a\u003e\n \u003ca href=\"https://github.com/roadrunner-server/endure/actions\"\u003e\u003cimg src=\"https://github.com/roadrunner-server/endure/workflows/Linux/badge.svg\" alt=\"\"\u003e\u003c/a\u003e\n \u003ca href=\"https://github.com/roadrunner-server/endure/actions\"\u003e\u003cimg src=\"https://github.com/roadrunner-server/endure/workflows/macOS/badge.svg\" alt=\"\"\u003e\u003c/a\u003e\n \u003ca href=\"https://github.com/roadrunner-server/endure/actions\"\u003e\u003cimg src=\"https://github.com/roadrunner-server/endure/workflows/Windows/badge.svg\" alt=\"\"\u003e\u003c/a\u003e\n \u003ca href=\"https://github.com/roadrunner-server/endure/actions\"\u003e\u003cimg src=\"https://github.com/roadrunner-server/endure/workflows/Linters/badge.svg\" alt=\"\"\u003e\u003c/a\u003e\n \u003ca href=\"https://codecov.io/gh/roadrunner-server/endure\"\u003e\u003cimg src=\"https://codecov.io/gh/roadrunner-server/endure/branch/master/graph/badge.svg?token=itNaiZ6ALN\"/\u003e\u003c/a\u003e\n \u003ca href=\"https://discord.gg/spiralphp\"\u003e\u003cimg src=\"https://img.shields.io/badge/discord-chat-magenta.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nRoadRunner is an open-source (MIT licensed) high-performance PHP application server, load balancer, and process manager.\nIt supports running as a service with the ability to extend its functionality on a per-project basis.\n\nRoadRunner includes PSR-7/PSR-17 compatible HTTP and HTTP/2 server and can be used to replace classic Nginx+FPM setup\nwith much greater performance and flexibility.\n\n# Join our discord server: [Link](https://discord.gg/TFeEmCs)\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://roadrunner.dev/\"\u003e\u003cb\u003eOfficial Website\u003c/b\u003e\u003c/a\u003e |\n\t\u003ca href=\"https://roadrunner.dev/docs\"\u003e\u003cb\u003eDocumentation\u003c/b\u003e\u003c/a\u003e |\n    \u003ca href=\"https://forum.roadrunner.dev\"\u003e\u003cb\u003eForum\u003c/b\u003e\u003c/a\u003e |\n    \u003ca href=\"https://github.com/orgs/roadrunner-server/projects/4\"\u003e\u003cb\u003eRelease schedule\u003c/b\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nEndure is an open-source (MIT licensed) plugin container with IoC (Inversion of Control).\n\n## Features\n\n- Supports interfaces (see examples)\n- Uses a graph to topologically sort, run, stop, and restart dependent plugins\n- Supports easy addition of Middleware plugins\n- Error reporting\n\n## Installation\n\n```go\ngo get -u github.com/roadrunner-server/endure/v2\n```\n\n\n### Why?\n\nImagine you have an application in which you want to implement a plugin system. These plugins can depend on each other (via interfaces or directly). For example, we have 3 plugins: HTTP (to communicate with the world), DB (to save the world), and logger (to see the progress). In this particular case, we can't start HTTP before we start all other parts. Also, we have to initialize the logger first, because all parts of our system need the logger. All you need to do in Endure is to pass the `HTTP`, `DB`, and `Logger` structs to Endure and implement the `Endure` interface. So, the dependency graph will be the following:\n\n![Dependency Graph](https://github.com/roadrunner-server/endure/blob/master/images/graph.png)\n\nFirst, we initialize the `endure` container:\n\n```go\nimport (\n    \"log/slog\"\n)\n\nfunc main() {\n    container := endure.New(slog.LevelDebug, endure.Visualize())\n}\n```\n\nLet's take a look at the `endure.New()` function:\n\n1. The first argument is the standard golang logger log level.\n2. The next arguments are optional and can be set using `Options`. For example, `endure.Visualize()` will show you a dot-compatible graph in the console. Then we need to pass our structures as references to the `RegisterAll` or `Register` function.\n\n\n```go\nerr = container.RegisterAll(\n    \u0026httpPlugin{},\n    \u0026DBPlugin{},\n    \u0026LoggerPlugin{},\n\t)\n    if err != nil {\n        panic(err)\n    }\n```\n\nThe order of plugins in the `RegisterAll` function does not matter.\nNext, we need to initialize and run our container:\n\n\n```go\nerr := container.Init()\n    if err != nil {\n        panic(err)\n}\nerrCh, err := container.Serve()\n    if err != nil {\n    \tpanic(err)\n}\n```\n\n\n`errCh` is the channel with errors from all `Vertices`. You can identify the vertex by `vertexID`, which is presented in the `errCh` struct. Then just process the events from the `errCh`:\n\n```go\nfor {\n    select {\n        case e := \u003c-errCh:\n            println(e.Error.Err.Error()) // just print the error, but actually error processing could be there\n            er := container.Stop()\n            if er != nil {\n                panic(er)\n            }\n        return\n    }\n}\n```\n\nThe start will proceed in topological order (Logger -\u003e DB -\u003e HTTP), and the stop in reverse-topological order automatically.\n\n### Endure main interface\n\n```go\npackage sample\n\nimport (\n\t\"context\"\n\t\n\t\"github.com/roadrunner-server/endure/v2/dep\"\n)\n\ntype (\n   // This is the main Endure service interface which may be implemented to Start (Serve) and Stop plugin (OPTIONAL)\n   Service interface {\n      // Serve\n      Serve() chan error\n      // Stop with context, if you reach the timeout, endure will force the exit via context deadline\n      Stop(context.Context) error\n      // Named return plugin's name\n      Named() string\n   }\n\n   // Provider declares the ability to provide dependencies to other plugins (OPTIONAL)\n   Provider interface {\n      Provides() []*dep.In\n   }\n\n   // Collector declares the ability to accept the plugins which match the provided method signature (OPTIONAL)\n   Collector interface {\n      Collects() []*dep.Out\n   }\n)\n\n// Init is mandatory to implement\ntype Plugin struct{}\n\nfunc (p *Plugin) Init( /* deps here */) error {\n   return nil\n}\n```\n\nOrder is the following:\n\n1. `Init() error` - is mandatory to implement. For your structure (which you pass to `Endure`), you should have this method as the method of the struct (```go func (p *Plugin) Init() error {}```). It can accept as a parameter any passed to the `Endure` structure (see samples) or interface (with limitations).\n2. `Service` - is optional to implement. It has 2 methods: `Serve` which should run the plugin and return an initialized golang channel with errors, and `Stop` to shut down the plugin. The `Stop` and `Serve` should not block the execution.\n3. `Provider` - is optional to implement. It is used to provide some dependency if you need to extend your struct without deep modification.\n4. `Collector` - is optional to implement. It is used to mark a structure (vertex) as some struct dependency. It can accept interfaces that implement a caller.\n5. `Named` - is mandatory to implement. This is a special kind of interface that provides the name of the struct (plugin, vertex) to the caller. It is useful in the logger (for example) to know the user-friendly plugin name.\n\nAvailable options:\n1. `Visualize`: Graph visualization option via graphviz. The Graphviz diagram can be shown via stdout.\n2. `GracefulShutdownTimeout`: `time.Duration`. How long to wait for a vertex (plugin) to stop.\n\nThe fully operational example is located in the `examples` folder.\n","funding_links":["https://github.com/sponsors/roadrunner-server"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froadrunner-server%2Fendure","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froadrunner-server%2Fendure","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froadrunner-server%2Fendure/lists"}