Gamend.LobbySnapshots.Writer (gamend_core v1.0.1192)

Copy Markdown View Source

Buffers snapshots and events and bulk-inserts them.

Buffering is the point: record_event/4 is called from inside the serialized game loop, where a synchronous DB round trip shows up as gameplay stutter. An enqueue is a cast and returns immediately.

This is a plain per-node process, not a singleton. Ordering comes from (inserted_at, id) with UUIDv7 ids, so nothing has to be centrally assigned and two nodes writing for the same lobby interleave correctly on read.

Durability is best-effort, deliberately. A run bad enough to take the node down is one worth keeping, so the buffer flushes on terminate/2 and holds at most 200ms of work. A failed flush discards its batch and counts it — that is what keeps a DB outage from growing the buffer without bound, degrading into lost history rather than an OOM that takes the server with it. stats/0 exposes the count so a silently-lossy writer stays visible.

Summary

Functions

Returns a specification to start this module under a supervisor.

Writer stats summed across the cluster.

Buffer an event.

Buffer a gathered snapshot. Sections arrive pre-hashed as %{name => {hash, content}}.

Flush synchronously. Used by tests and by callers that need the write visible.

Buffer depth and dropped-row count for this node's writer.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

cluster_stats()

@spec cluster_stats() :: %{
  buffered: non_neg_integer(),
  dropped: non_neg_integer(),
  nodes: pos_integer(),
  unreachable: non_neg_integer()
}

Writer stats summed across the cluster.

Each node buffers independently, so reading only the local process would under-report dropped rows — and a silently-lossy writer is the one thing the admin view most needs to show. Unreachable nodes are counted rather than failing the call, so the number is never quietly wrong without saying so.

enqueue_event(attrs)

@spec enqueue_event(map()) :: :ok

Buffer an event.

enqueue_snapshot(attrs)

@spec enqueue_snapshot(map()) :: :ok

Buffer a gathered snapshot. Sections arrive pre-hashed as %{name => {hash, content}}.

flush()

@spec flush() :: :ok

Flush synchronously. Used by tests and by callers that need the write visible.

start_link(opts)

stats()

@spec stats() :: %{buffered: non_neg_integer(), dropped: non_neg_integer()}

Buffer depth and dropped-row count for this node's writer.