View Source Chord (Chord v0.2.0)
Chord: A powerful library for managing real-time contexts with efficiency and flexibility.
The Chord
module serves as the library's entry point, providing a high-level API for managing contexts, tracking deltas, and integrating with various storage backends.
It is designed to simplify state synchronization and lifecycle management in real-time applications.
Key Features
- Context management: Create, update, synchronize, and delete contexts seamlessly.
- Delta tracking: Efficiently track changes to minimize data transfer.
- Flexible backends: Built-in support for ETS (in-memory) and Redis (distributed).
- Context export: Easily export contexts to external storage systems.
- Customizable cleanup: Automate or manually clean up expired data.
- Partial updates: Update specific fields within a context.
- Context export: Easily export contexts to external storage.
- External context provider: Restore contexts from external sources as needed.
Configuration
Chord is highly configurable via the application environment. Below are the available options:
config :chord,
backend: Chord.Backend.ETS, # Backend for storing contexts and deltas (ETS or Redis)
context_auto_delete: true, # Enable automatic cleanup of expired contexts
context_ttl: 6 * 60 * 60, # Time-to-live for contexts
delta_ttl: 3 * 60 * 60, # Time-to-live for deltas
delta_threshold: 100, # Maximum number of deltas to retain per context
delta_formatter: Chord.Delta.Formatter.Default, # Delta formatter (default or custom)
time_provider: MyApp.TimeProvider, # Custom time provider for timestamps (optional)
time_unit: :second, # Unit for timestamps (:second or :millisecond)
export_callback: &MyApp.ContextExporter.export/1, # Callback for exporting contexts (optional)
context_external_provider: &MyApp.ExternalState.fetch_context/1 # Restore contexts from external storage (optional)
Common Options
The following options are shared across several functions in this module and related modules:
- :context_id - The identifier for the context.
- :version - The version number for tracking state changes.
- :inserted_at - The timestamp when the context or delta was created.
- :limit - The maximum number of contexts or deltas to fetch.
- :offset - The number of entries to skip when fetching.
- :order - The sort order for results (:asc or :desc).
Summary
Functions
Triggers a one-time cleanup for stale contexts and deltas.
Deletes the global context, including all associated deltas.
Exports the active context for a given identifier to external storage using the configured export callback.
Retrieves the current global context for a given identifier.
Restores a context from an external provider to the current backend.
Sets the global context and records deltas.
Starts the Cleanup.Server for periodic cleanup.
Stops the Cleanup.Server if running.
Synchronizes the context for a client based on its current version.
Updates the backend options for the cleanup server at runtime.
Updates the cleanup server's interval at runtime.
Partially updates the global context for a given identifier.
Functions
@spec cleanup(opts :: Keyword.t()) :: :ok
Triggers a one-time cleanup for stale contexts and deltas.
Parameters
opts
(Keyword.t): Optional parameters for filtering contexts and deltas (see "Common Options").
Returns
:ok
on success.
Examples
iex> Chord.cleanup(limit: 10)
Deletes the global context, including all associated deltas.
This function removes the context identified by context_id
from the backend, along with
all deltas related to that context. Once deleted, the context cannot be restored unless it is backed up externally.
Parameters
context_id
(any): The identifier for the context. This should uniquely represent the context.
Returns
:ok
on success, confirming that the context and its deltas were deleted.{:error, term()}
for other types of failures.
Examples
iex> Chord.delete_context("user:369")
:ok
iex> Chord.delete_context("user:non-existent")
{:error, :not_found}
Exports the active context for a given identifier to external storage using the configured export callback.
This function retrieves the current context for the specified context_id
and sends it
to an external storage provider via the callback defined in the application configuration.
Parameters
context_id
(any): The identifier for the context. This should uniquely represent the context.
Returns
:ok
if the context is successfully exported to the external storage.{:error, :not_found}
if the specified context does not exist.{:error, term()}
for other types of failures.
Examples
iex> Chord.export_context("user:123")
:ok
iex> Chord.export_context("user:non-existent")
{:error, :not_found}
Retrieves the current global context for a given identifier.
This function fetches the context associated with the given context_id
. If the context
does not exist or an invalid context_id
is provided, an error is returned.
Parameters
context_id
(any): The identifier for the context. This should uniquely represent the context.
Returns
{:ok, map()}
on success, where the map contains the context data.{:error, :not_found}
if the context does not exist.{:error, term()}
for other types of failures.
Examples
iex> Chord.get_context("user:369")
{:ok,
%{
version: 1,
context: %{status: "online", metadata: %{language: "en-US", theme: "light"}},
context_id: "user:369",
inserted_at: 1737892321
}}
iex> Chord.get_context("user:non-existent")
{:error, :not_found}
Restores a context from an external provider to the current backend.
This function retrieves a context from an external storage provider (e.g., a database or cloud storage) and stores it in the current backend for future use.
Parameters
context_id
(any): The identifier for the context. This should uniquely represent the context.
Returns
{:ok, map()}
on success, where the map represents the restored context.{:error, :not_found}
if the context is not found in the external storage.{:error, term()}
for other types of failures.
Examples
iex> Chord.restore_context("user:369")
{:ok,
%{
version: 10,
context: %{source: "external storage provider"},
inserted_at: 1737464001,
context_id: "user:369"
}}
iex> Chord.restore_context("user:non-existent")
{:error, :not_found}
Sets the global context and records deltas.
This function allows you to set a new global context for a specific identifier and automatically calculates deltas for any changes.
Parameters
context_id
(any): The identifier for the context. This should uniquely represent the context.new_context
(map): The new context to be stored. This should be a map containing the desired state.
Returns
{:ok, %{context: map(), delta: map()}}
on success.{:error, term()}
on failure.
Examples
iex> Chord.set_context("user:369", %{status: "online", metadata: %{theme: "light", language: "en-US"}})
{:ok,
%{
context: %{
version: 1,
context: %{
status: "online",
metadata: %{language: "en-US", theme: "light"}
},
context_id: "user:369",
inserted_at: 1737892321
},
delta: %{
version: 1,
context_id: "user:369",
delta: %{
status: %{value: "online", action: :added},
metadata: %{
language: %{value: "en-US", action: :added},
theme: %{value: "light", action: :added}
}
},
inserted_at: 1737892321
}
}}
Starts the Cleanup.Server for periodic cleanup.
Parameters
opts
- Options for the Cleanup.Server. Examples include::interval
- The interval (in milliseconds) between cleanup executions.:backend_opts
- A keyword list of options passed to backend listing functions (see "Common Options").
Returns
{:ok, pid}
on success.{:error, reason}
if an error occurs when starting the cleanup server process.
Examples
iex> Chord.start_cleanup_server(interval: 60000)
{:ok, #PID<0.247.0>}
@spec stop_cleanup_server() :: :ok
Stops the Cleanup.Server if running.
Returns
:ok
on success.
Examples
iex> Chord.stop_cleanup_server()
:ok
@spec sync_context(context_id :: any(), client_version :: integer() | nil) :: {:full_context, map()} | {:delta, map()} | {:no_change, integer()}
Synchronizes the context for a client based on its current version.
This function ensures that the client has the latest version of the context identified by context_id
.
Depending on the client's version, it will return either the full context, the delta of changes, or indicate
that no synchronization is necessary.
Parameters
context_id
(any): The identifier for the context. This should uniquely represent the context.client_version
(integer): The last known version of the context for the client.
Returns
{:full_context, map()}
: Returns the entire context if the client is too far behind or has no version.{:delta, map()}
: Returns only the changes (deltas) required to update the client to the latest version.{:no_change, version}
: Indicates that the client's version is already up-to-date and no synchronization is needed.
Examples
iex> Chord.sync_context("user:369", nil)
{:full_context,
%{
version: 2,
context: %{status: "online", metadata: %{language: "en-US", theme: "dark"}},
context_id: "user:369",
inserted_at: 1737893007
}}
iex> Chord.sync_context("user:369", 1)
{:delta,
%{
version: 2,
context_id: "user:369",
delta: %{
metadata: %{theme: %{value: "dark", action: :modified, old_value: "light"}}
},
inserted_at: 1737893007
}}
iex> Chord.sync_context("user:369", 2)
{:no_change, 2}
@spec update_cleanup_backend_opts(new_opts :: Keyword.t()) :: :ok
Updates the backend options for the cleanup server at runtime.
Parameters
new_opts
(Keyword.t): The new backend options.
Returns
:ok
on success.
Examples
iex> Chord.update_cleanup_backend_opts([limit: 100])
:ok
@spec update_cleanup_interval(new_interval :: integer()) :: :ok
Updates the cleanup server's interval at runtime.
Parameters
new_interval
(integer): The new interval in milliseconds.
Returns
:ok
on success.
Examples
iex> Chord.update_cleanup_interval(30000)
:ok
Partially updates the global context for a given identifier.
This function applies the given changes to the existing context identified by context_id
.
It calculates the delta for the updated fields and returns the updated context and delta.
Parameters
context_id
(any): The identifier for the context. This should uniquely represent the context.changes
(map): A map of fields to be updated in the existing context. The keys in this map must correspond to valid fields in the context, or, if a specified path does not exist, it will be added as a new field at the root level of the context.
Returns
{:ok, %{context: map(), delta: map()}}
on success, where:context
is the updated context.delta
is a map representing the changes made.
{:error, :not_found}
if the context does not exist.{:error, term()}
for other types of failures.
Examples
iex> Chord.update_context("user:369", %{metadata: %{theme: "dark"}})
{:ok,
%{
context: %{
version: 2,
context: %{status: "online", metadata: %{language: "en-US", theme: "dark"}},
context_id: "user:369",
inserted_at: 1737893007
},
delta: %{
version: 2,
context_id: "user:369",
delta: %{
metadata: %{
theme: %{value: "dark", action: :modified, old_value: "light"}
}
},
inserted_at: 1737893007
}
}}
iex> Chord.update_context("user:non-existent", %{metadata: %{theme: "dark"}})
{:error, :not_found}