{"id":17370112,"url":"https://github.com/gianarb/planner","last_synced_at":"2025-04-15T03:32:16.060Z","repository":{"id":44552746,"uuid":"206373484","full_name":"gianarb/planner","owner":"gianarb","description":"planner where R stays for reactive. It is a library to implement the reactive planning in Go.","archived":false,"fork":false,"pushed_at":"2024-01-24T12:37:35.000Z","size":44,"stargazers_count":13,"open_issues_count":4,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-01T08:42:23.782Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://godoc.org/github.com/gianarb/planner","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/gianarb.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-04T17:21:07.000Z","updated_at":"2024-03-17T00:57:14.000Z","dependencies_parsed_at":"2024-06-19T17:39:34.181Z","dependency_job_id":"1ce592bd-330c-49c8-9224-07fe479c9860","html_url":"https://github.com/gianarb/planner","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gianarb%2Fplanner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gianarb%2Fplanner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gianarb%2Fplanner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gianarb%2Fplanner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gianarb","download_url":"https://codeload.github.com/gianarb/planner/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223657852,"owners_count":17181024,"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-10-16T00:23:35.416Z","updated_at":"2024-11-08T09:04:27.555Z","avatar_url":"https://github.com/gianarb.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## planner\n\nPlanner is a library I wrote to implement reactive planning in Go.\n\nFirst what is reactive planning? I will leave you a few links:\n\n* [Reactive planning from Wikipedia](https://en.wikipedia.org/wiki/Reactive_planning)\n* [The book \"Thinking in Systems\"](https://gianarb.it/blog/thinking-in-systems-donella-meadows-review)\n* [AWS re:Invent 2018: Close Loops \u0026 Opening Minds: How to Take Control of Systems, Big \u0026 Small ARC337](https://www.youtube.com/watch?v=O8xLxNje30M\u0026feature=emb_title)\n* [Me explaining on Twitch this library with an example](https://www.twitch.tv/videos/770165588)\n\n## Reactive planning implementation in planner\nIn short a reactive plan empower a humanoid robot the reconcile and stay up when\nyou push it.\n\nOr it keeps your Kubernetes resources such as Pods, Services, Ingress and\nDeployment up and running.\n\nIt is made of three parts:\n\n1. A plan\n2. A set of procedures\n3. A scheduler\n\nA **procedure** is the smallest unit of work that you can think about:\n\n1. Create an AWS EC2\n2. Control the location of a device\n3. Do a server healthcheck\n\nA **plan** is a set of **procedures**. If we look at how a replication\ncontroller works (AWS Autoscaling Group or Kubernetes Replicaset) we can think\nabout a set of common steps like:\n\n1. Find the list of available servers or pods for that particular replicaset or\n   autoscaling group\n2. Do a healthcheck on all the servers/pod\n3. Based on how many of them are healthy there are other 2 steps:\n    4. Create a new EC2/Pod\n    5. Delete an EC2/Pod\n\nThose are 5 **procedures**, together they are a Reconciliation plan.\n\nThe **scheduler** takes a plan and execute it until there is nothing left to do.\n\nA plan has a `Create` function that calculates and returns the **procedures**\nthat has to be executed. Iteration over iteration the number of **procedures** can\nchange.\n\nYour **plan** can succeed at the first iteration, it means that the second one will\nreturn zero **procedures** and the scheduler will stop executing the plan.\n\nIf there are left over action to be done they will be picked up during a future\nexecution.\n\nA scheduler stops to execute a plan only if:\n\n1. There are not left over procedures for a particular plan (it is all done!\n   Great)\n2. A procedure returns an `error`\n\nEach **procedure** can return multiple procedures, in this way you mitigate the\namount of errors you have to return, zero is your target! Any `error` you\nencounter is an opportunity to code a mitigation as separate procedure. Sometime\nyou have to just wait, sometime you can trigger a page and wait until human\nfixes it.\n\n## Example\n\nI would like to measure random and luck! So I would like to write a program that\ngiven a number tries its best to get there just via random additions and\nsubtraction [you can start from here](https://play.golang.com/p/0LuIoMtp10f)\nusing reactive planning.\n\nIf you execute the program in its current form it will get this output:\n\n```console\n1.257894e+09\tinfo\tplanner@v0.0.1/scheduer.go:41\tStarted execution plan count_plan\t{\"execution_id\": \"befecb26-1c94-4a61-8305-c9b40aa63331\"}\n1.257894e+09\tinfo\tplanner@v0.0.1/scheduer.go:59\tPlan executed without errors.\t{\"execution_id\": \"befecb26-1c94-4a61-8305-c9b40aa63331\", \"execution_time\": \"0s\", \"step_executed\": 20}\n```\n\nThe plan is a success in 20 steps. Because as you can see there is only one\nprocedures who increments by one. So starting from zero it takes 20 steps to get\nto my desired number 20. That's great to get the vibe of the project, but we\nneed more.\n\nSuggested evolution:\n\n* Change the AddNumber to use a randomly generated number\n* Add a condition in the `Create` that looks like this:\n\n```go\n\tif p.current \u003c p.Target {\n\t\treturn []planner.Procedure{\u0026AddNumber{plan: p}}, nil\n\t} else {\n\t\treturn []planner.Procedure{\u0026SubtractNumber{plan: p}}, nil\n    }\n```\nAnd write `SubtractNumber` in the same way `AddNumber` works but with `-`.\n\n## Are you using this library\n\nAdd your project to [ADOPTERS.md](./ADOPTERS.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgianarb%2Fplanner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgianarb%2Fplanner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgianarb%2Fplanner/lists"}