ferry
Members list
Type members
Classlikes
Attributes
- Companion
- trait
- Source
- Ferry.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Ferry.type
Coalesces individual calls into batched calls to an external system, and limits the load put on it.
Coalesces individual calls into batched calls to an external system, and limits the load put on it.
Each input submitted through apply is queued. Queued inputs are dispatched together in a single batch call when maxBatchSize inputs have accumulated, or at the latest maxBatchDelay after the oldest of them was submitted. At most maxInFlightBatches batch calls run at the same time, and at most maxQueueing inputs wait for a batch: beyond that, calls are rejected immediately rather than piling up.
Every caller receives its own share of the batch result, or the batch call's failure.
Attributes
- Companion
- object
- Source
- Ferry.scala
- Supertypes
-
class Objecttrait Matchableclass Any
Attributes
- Companion
- class
- Source
- FerryConfig.scala
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
FerryConfig.type
Validated settings for a Ferry. Construct with FerryConfig.make.
Validated settings for a Ferry. Construct with FerryConfig.make.
Value parameters
- maxBatchDelay
-
A partial batch is dispatched at the latest this long after its oldest input was submitted (or as soon as a batch slot frees up, if all slots were busy at that moment).
Duration.Zerodispatches whatever is waiting immediately. - maxBatchSize
-
A batch is dispatched as soon as it holds this many inputs.
- maxInFlightBatches
-
Maximum number of batch calls running concurrently.
- maxQueueing
-
Maximum number of inputs waiting for a batch. Further inputs are rejected with FerryError.Rejected.
Attributes
- Companion
- object
- Source
- FerryConfig.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Why a call made through a Ferry did not produce a result.
Why a call made through a Ferry did not produce a result.
Attributes
- Source
- FerryError.scala
- Supertypes
-
trait Enumtrait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Source
- FerryError.scala
- Supertypes
-
trait Producttrait Equalsclass Exceptionclass Throwabletrait Serializableclass Objecttrait Matchableclass AnyShow all
A batch call for inputs that must be applied in order to one key's state, in a store with conditional writes: read the state once, apply the batch's inputs to it in order, in memory, and write the result once, only if the store still holds the state that was read. A failed read or write, a conflict included, retries the whole round trip.
A batch call for inputs that must be applied in order to one key's state, in a store with conditional writes: read the state once, apply the batch's inputs to it in order, in memory, and write the result once, only if the store still holds the state that was read. A failed read or write, a conflict included, retries the whole round trip.
Each input gets its own outcome, computed when it is applied, from the state at that point: an input that changes how later ones apply, such as one closing a period, does so inside the fold. An input rejected on its own merits fails no other. A store that writes the result in two steps, a commit and a projection, uses ProjectedWrite. step sees the state as read, which includes inputs that an earlier attempt already applied (a write can land and its response be lost): it should answer such an input without applying it again, so that retrying is safe (see docs/decisions/0005).
Use it as the call and the extract of Ferry.perKey:
val write = FoldWrite(id = (e: Entry) => e.id, read = store.read, step = apply, write = store.writeIf, retry = policy)
Ferry.perKey(config, (e: Entry) => e.entity)(write.call)(write.outcome)
Value parameters
- id
-
Identifies an input. Inputs of one batch with the same id are applied once, and share the first one's outcome.
- read
-
Reads a key's state, including whatever makes the write conditional, such as a version.
- retry
-
When to retry the round trip after
readorwritefailed. - step
-
Applies one input to the state: the next state and the input's outcome. It must be pure; it runs again on retry.
- write
-
Writes
afterforkeyif the store still holdsbefore, and fails otherwise. Called only when the batch changed the state (after != before).
Attributes
- Source
- FoldWrite.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Companion
- class
- Source
- FerryConfig.scala
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
InvalidConfig.type
Attributes
- Companion
- object
- Source
- FerryConfig.scala
- Supertypes
-
trait Producttrait Equalsclass IllegalArgumentExceptionclass RuntimeExceptionclass Exceptionclass Throwabletrait Serializableclass Objecttrait Matchableclass AnyShow all
Attributes
- Source
- Lanes.scala
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
Lanes.type
Attributes
- Companion
- trait
- Source
- Order.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Order.type
The order in which a Ferry.perKey sends a key's waiting inputs: ascending rank, ties in arrival order.
The order in which a Ferry.perKey sends a key's waiting inputs: ascending rank, ties in arrival order.
Inputs that wait together are sent in rank order, so each batch is in rank order and, under load, so is everything that arrived during the previous round trip. An input that arrives after inputs of a higher rank were already sent is not held back or rejected: it goes in the key's next batch, and the downstream, which holds the key's state, decides where it belongs. To give out-of-order inputs more time to meet, set a positive maxBatchDelay.
rank is evaluated once per input, when it is submitted. It must be pure, total and cheap.
Implement it to rank by anything an input carries, e.g. an effective date as date.toEpochDay, a timestamp as epoch milliseconds, or a sequence number.
Attributes
- Companion
- object
- Source
- Order.scala
- Supertypes
-
class Objecttrait Matchableclass Any
Attributes
- Companion
- class
- Source
- PerKeyConfig.scala
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
PerKeyConfig.type
Validated settings for a Ferry.perKey. Construct with PerKeyConfig.make.
Validated settings for a Ferry.perKey. Construct with PerKeyConfig.make.
Value parameters
- directIdleKeys
-
Whether, with a zero
maxBatchDelay, an idle key's input is sent at once by its own caller (the default), or by a worker like any batch. Turn it off when the downstream needs a hard bound on concurrent calls: direct calls are not counted againstmaxInFlightBatches. - maxBatchDelay
-
How long a partial batch may wait for more inputs after its oldest input was submitted. The default, zero, sends an idle key's input at once, directly from its caller, and whatever is waiting as soon as the key's previous call completes: under load batches then grow by themselves, at no added latency. A positive delay batches every input, even an idle key's.
- maxBatchSize
-
A key's batch is dispatched as soon as it holds this many inputs.
- maxBatchWeight
-
A key's batch is dispatched as soon as its inputs weigh this much in total, and never carries more, except for a single input that is heavier on its own: it travels alone. Use it to stay under a per-request byte limit downstream.
- maxInFlightBatches
-
Maximum number of batch calls running concurrently, across all keys. Each key has at most one. Direct calls for idle keys are not counted.
- maxQueuedWeight
-
Maximum total weight of the inputs waiting, across all keys. Further inputs are rejected with FerryError.Rejected. With weights in bytes, this bounds the memory held by waiting inputs.
- maxQueueing
-
Maximum number of inputs waiting, across all keys. Further inputs are rejected with FerryError.Rejected.
Attributes
- Companion
- object
- Source
- PerKeyConfig.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Companion
- class
- Source
- ProjectedWrite.scala
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
ProjectedWrite.type
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).
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:
readreads the record, including its fence and its projection marker;stepreturns the state the commit stores, for whichpendingholds exactly when there is something to project;writeis 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.retryapplies 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
stateand clears its marker. For a view of one object: writes it only if the store still holdsstate, fence and marker alike, fails otherwise, and answersProjection.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 holdsstate; answers the entries still pending, each with why. It derives rows and ids fromstatealone: resume has no inputs. A failure means no verdict: the call re-reads and retries it withfold.retry. A verdict with entries pending is final for the call; the store owns its per-row retries.
Attributes
- Companion
- object
- Source
- ProjectedWrite.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all