{"id":25221465,"url":"https://github.com/sampscl/external_state","last_synced_at":"2025-04-05T11:22:28.645Z","repository":{"id":62429489,"uuid":"183788924","full_name":"sampscl/external_state","owner":"sampscl","description":"Store state, as a properties structure, externally to a process.","archived":false,"fork":false,"pushed_at":"2019-09-25T13:53:07.000Z","size":26,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-03-11T22:22:49.144Z","etag":null,"topics":["elixir","state-management"],"latest_commit_sha":null,"homepage":null,"language":"Elixir","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/sampscl.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":"2019-04-27T15:18:14.000Z","updated_at":"2019-09-25T13:53:03.000Z","dependencies_parsed_at":"2022-11-01T20:05:26.224Z","dependency_job_id":null,"html_url":"https://github.com/sampscl/external_state","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sampscl%2Fexternal_state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sampscl%2Fexternal_state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sampscl%2Fexternal_state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sampscl%2Fexternal_state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sampscl","download_url":"https://codeload.github.com/sampscl/external_state/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247326821,"owners_count":20920915,"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":["elixir","state-management"],"created_at":"2025-02-10T22:34:40.982Z","updated_at":"2025-04-05T11:22:28.624Z","avatar_url":"https://github.com/sampscl.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ExternalState\n\nStore state, as a properties structure, externally to a process.\n\n## Motivation\n\nA process in Elixir stores data in its state that other processes may need -- a\ncurrent status flag for instance. The standard way of sharing this data is to\nprovide an API that results in a GenServer call. But, what if the GenServer\nis busy working on a long-running job? You could break your long running jobs\ninto pieces and allow the GenServer to check its message queue. Yuck,\ncooperative multitasking and added complexity. You could create an ETS table or\nother external database record. Yuck, verbose, complex, and high-friction solution\nto what should be a simple problem.\n\nExternalState helps solve this problem by providing a clean way of stashing\nsome or all of your state in a data structure managed by a different process.\n\nCaveat lector: this works beautifully for named workers but doesn't work well\nwith simple 1-for-1 workers because the state is managed using the module name.\n\n## Usage\n```elixir\ndefmodule MyGenserver do\n  use ExternalState, persist: false, props: [foo: true]\n\n  def init(:ok) do\n    init_ex_state() # external state is now at the defaults specified in use\n  end\n\n  # ...\n\n  def do_foo do\n    # ... something that sets foo to true ...\n    merge_ex_state(foo: true)\n  end\n\n  def undo_foo do\n    # ... something that sets foo to false ...\n    merge_ex_state(foo: false)\n    # or: merge_ex_state(%{foo: false})\n  end\n\n  def foo? do\n    get_ex_state().foo\n  end\n\nend\n```\n\n## API\nThe following are added to your module when you `use` ExternalState:\n\n- `@ex_state_struct` An atom name for your external state structure\n- `default_ex_state/0` Get a state structure with default values from props\n- `init_ex_state/0` Initialize your external state; must call once, multiple calls are okay\n- `get_ex_state/0` Get the current external state or nil if no init yet\n- `put_ex_state/1` Set the external state, returns the state or nil if no init yet\n- `merge_ex_state/1` Update the external state with values from the\n  parameter, which can be a keyword list of keys and values or a map. Returns\n  the updated state or nil if no init yet.\n\nIf ExternalState is `use`d with `persist: true`, then the external state will\nremain valid after the process that calls `init_ex_state/0` exits. This\nis the default.\n\n## Installation\n\nThe package can be installed by adding `external_state` to your list of\ndependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:external_state, \"~\u003e 1.0.6\"}\n  ]\nend\n```\n\nThe docs can be found at [https://hexdocs.pm/external_state](https://hexdocs.pm/external_state).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsampscl%2Fexternal_state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsampscl%2Fexternal_state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsampscl%2Fexternal_state/lists"}