ProjectedWrite

ferry.ProjectedWrite
See theProjectedWrite companion object
final case class ProjectedWrite[-R, E, K, I, Id, S, O](fold: FoldWrite[R, E, K, I, Id, S, O], pending: S => Boolean, project: (K, S) => ZIO[R, E, Projection[Id, E]])

A batch call for a store that writes a key's record in two dependent conditional writes: commit the folded state (fold.write, fenced on the state read), then project it into its read-side view (project, fenced on the committed record being as committed). The record says whether its projection is pending (pending), so a projection that did not happen, because the process failed or died between the writes, is finished later by resume, from the store, by any process. Nothing is kept between calls: the marker lives in the store (see docs/decisions/0014).

The view may be one object per record, written whole by project, or one row per entry, each its own write (see docs/decisions/0015). In either case project answers with what it left pending: nothing, or the entries whose row is not in the view, each with why. An input whose row is in the view when the call returns is ProjectedWrite.Outcome.Projected; any other is ProjectedWrite.Outcome.Committed, carrying why: it is durable, and the view may or may not include it yet. The call fails only when the commit is not known to have happened, and retrying it is then safe, because step answers inputs already applied; a failed projection is reported, not failed, because the inputs are durable (see docs/decisions/0006).

Use it as the call and the extract of Ferry.perKey, like FoldWrite:

val write = ProjectedWrite(FoldWrite(_.id, store.read, apply, store.commit, policy), pending, store.projectRows)
Ferry.perKey(config, (e: Entry) => e.entity)(write.call)(write.outcome)

Value parameters

fold

The commit phase: read reads the record, including its fence and its projection marker; step returns the state the commit stores, for which pending holds exactly when there is something to project; write is the commit. The commit must never move the stored marker backwards: either it leaves the marker as stored, or it is fenced on the whole record read, marker included. retry applies to the commit, and to resume after a first projection attempt failed; that first attempt's error is not passed to it.

pending

Whether a state, as read or as committed, has a projection to write. It must be pure.

project

Writes the view of state and clears its marker. For a view of one object: writes it only if the store still holds state, fence and marker alike, fails otherwise, and answers Projection.complete; see ProjectedWrite.wholeRecord. For a view of one row per entry: writes each missing row, each write idempotent (a row already present is present, not an error); clears the marker only when every row is present, and only if the store still holds state; answers the entries still pending, each with why. It derives rows and ids from state alone: resume has no inputs. A failure means no verdict: the call re-reads and retries it with fold.retry. A verdict with entries pending is final for the call; the store owns its per-row retries.

Attributes

Companion
object
Source
ProjectedWrite.scala
Graph
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all

Members list

Value members

Concrete methods

def call(key: K, inputs: NonEmptyChunk[I]): ZIO[R, E, Map[Id, Outcome[E, O]]]

The batch call: one outcome per distinct input id. Fails only when the commit is not known to have happened.

The batch call: one outcome per distinct input id. Fails only when the commit is not known to have happened.

Attributes

Source
ProjectedWrite.scala
def outcome(input: I, outcomes: Map[Id, Outcome[E, O]]): Outcome[E, O]

One input's share of the batch result.

One input's share of the batch result.

Attributes

Source
ProjectedWrite.scala
def resume(key: K): ZIO[R, E, Projection[Id, E]]

Projects the key's record if its projection is pending, and does nothing otherwise; retried with fold.retry. Answers what is still pending: nothing, or the entries whose row is still missing, each with why. Safe to run anywhere, at any time, concurrently with the key's batches and with other calls of resume: rows are idempotent and the fence on the marker's clear refuses a stale projection. For sweepers, which find pending keys with a query of the store's own.

Projects the key's record if its projection is pending, and does nothing otherwise; retried with fold.retry. Answers what is still pending: nothing, or the entries whose row is still missing, each with why. Safe to run anywhere, at any time, concurrently with the key's batches and with other calls of resume: rows are idempotent and the fence on the marker's clear refuses a stale projection. For sweepers, which find pending keys with a query of the store's own.

Attributes

Source
ProjectedWrite.scala

Inherited methods

def productElementNames: Iterator[String]

Attributes

Inherited from:
Product
def productIterator: Iterator[Any]

Attributes

Inherited from:
Product