LemonCore.Store.Hooks (lemon_core v0.1.0)

View Source

Registration and safe invocation of LemonCore.Store extension points.

LemonCore.Store is a storage primitive: it must not know about run history, memory ingest, Telegram, or any other domain. Collaborators attach to it instead, either through configuration or at runtime.

Extension points

Hook shapes

The payload is always passed as the last argument:

{module, function}          # module.function(payload)
{module, function, args}    # module.function(arg1, ..., payload)
fun                         # fun.(payload) — 1-arity, runtime only

Configuration vs runtime registration

Configured values (start_link/1 opts, falling back to Application.get_env(:lemon_core, store_name)) are resolved when the store starts. Runtime registrations live in :persistent_term keyed by store name, so they survive a store crash and can be made before the store boots.

LemonCore.Store.register_finalize_run_hook({MyApp.Archive, :on_run})
LemonCore.Store.register_cached_table(:my_index)

Invocation is isolated: a hook that raises, throws, or exits is logged and skipped so one bad collaborator cannot take down the store.

Summary

Functions

Invoke every hook with payload, isolating failures.

Publish a store's resolved value for a kind, for client-side reads.

Read a store's published value for a kind.

Add a runtime registration for store, appended after existing ones.

List runtime registrations for store.

Call fun, returning fallback if it raises, throws, or exits.

Remove a runtime registration.

Types

hook()

@type hook() :: {module(), atom()} | {module(), atom(), [term()]} | (term() -> any())

kind()

@type kind() :: :finalize_run_hooks | :cached_tables

Functions

invoke(hooks, payload, context \\ [])

@spec invoke([hook()], term(), keyword()) :: :ok

Invoke every hook with payload, isolating failures.

Hooks run in registration order, in the caller's process. context is used only for log messages.

publish(store, kind, value)

@spec publish(atom(), kind(), term()) :: :ok

Publish a store's resolved value for a kind, for client-side reads.

Written by the store as it starts; read from caller processes that need to know the effective configuration without a round trip through the GenServer.

published(store, kind, default \\ [])

@spec published(atom(), kind(), term()) :: term()

Read a store's published value for a kind.

register(store, kind, value)

@spec register(atom(), kind(), term()) :: :ok

Add a runtime registration for store, appended after existing ones.

Registration order is preserved, and re-registering the same value is a no-op, so a collaborator that restarts does not accumulate duplicates.

registered(store, kind)

@spec registered(atom(), kind()) :: [term()]

List runtime registrations for store.

safely(fun, fallback, context \\ [])

@spec safely((-> result), result, keyword()) :: result when result: term()

Call fun, returning fallback if it raises, throws, or exits.

Used for collaborator calls made from inside the store process, where an exception would otherwise take the store down with it.

unregister(store, kind, value)

@spec unregister(atom(), kind(), term()) :: :ok

Remove a runtime registration.