> ## Documentation Index
> Fetch the complete documentation index at: https://s2.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Concurrency Control

> Coordinate writes with conditional appends using a match sequence number or fencing token.

Conditional appends coordinate writers against a durable stream. They let a writer append only when the stream is at an expected position or when the writer holds the expected fencing token.

This is useful for single-writer systems that need safe failover. A replacement writer can inspect the stream, determine the next expected position, and use a conditional append to avoid writing against stale state.

## Mechanisms

The [`append` API](/api/records/append) supports two concurrency-control mechanisms:

### Match sequence number

Specifying expected current state allows *optimistic* concurrency control.

You can provide the sequence number that you expect S2 to assign to the first record in a batch as the `match_seq_num`.

If it does not match, this will result in a [`412 Precondition Failed`](/api/error-codes#append-condition-failed-412) status or corresponding SDK error type.

<Tip>
  Conditional appends with an appropriate [retry policy](/sdk/retries-timeouts#append-retry-policy) can be used to achieve "exactly-once" semantics.
</Tip>

### Fencing tokens

Fencing is a form of *pessimistic* concurrency control.

It is a cooperative mechanism, so an append that does not specify a fencing token will still be allowed.

When an append does include a `fencing_token` and it does not match, this results in a [`412 Precondition Failed`](/api/error-codes#append-condition-failed-412) status or corresponding SDK error type.

<Tip>
  Setting the fencing token involves appending a `fence` [command record](/concepts/command-records#operations).
</Tip>

#### Fencing example

Set a fencing token via the CLI:

```bash theme={null}
s2 fence s2://my-basin/my-stream "writer-1"
```

Subsequent appends that specify a token will be rejected if it doesn't match:

```bash theme={null}
s2 append s2://my-basin/my-stream -f "writer-1"
```

Fencing tokens can be up to 36 UTF-8 bytes. An empty token clears the fence. Fencing is strongly consistent — once set, subsequent appends specifying a different token are immediately rejected.

## Failure handling

Append condition failures return structured [`412` error bodies](/api/error-codes#append-condition-failed-412) that identify the current fencing token or assignable sequence number.

<Info>
  In an append session, such a failure poisons the session. Establish a new session before continuing to write.
</Info>

## Ownership patterns

Conditional appends enforce write-side preconditions at S2.

On the read side, any reader can ensure its knowledge of the stream is current by making a [`check-tail`](/api/records/check-tail) call.

This round-trip can be avoided by a single logical owner of a stream using a [lease](https://en.wikipedia.org/wiki/Lease_\(computer_science\)). The lease itself may be modeled on top of the S2 stream by periodically appending application-level heartbeats identifying the current physical owner.

<Tip>
  AWS MemoryDB is built on an internal replicated log primitive that offers conditional appends. See §4 of [their paper](https://assets.amazon.science/e0/1b/ba6c28034babbc1b18f54aa8102e/amazon-memorydb-a-fast-and-durable-memory-first-cloud-database.pdf).

  S2 exposes this kind of primitive as a serverless cloud resource, so applications can model many durable streams with independent logical owners, including [agent sessions](https://s2.dev/blog/agent-sessions) and [multiplayer rooms](https://s2.dev/blog/durable-yjs-rooms).
</Tip>

## See also

<CardGroup cols={3}>
  <Card title="Appends" icon="pen" href="/concepts/appends">
    Understand append acknowledgements, batching, and durability.
  </Card>

  <Card title="Command records" icon="binary" href="/concepts/command-records">
    See how S2 applies fence and trim directives from records.
  </Card>

  <Card title="Append condition failures" icon="circle-exclamation" href="/api/error-codes#append-condition-failed-412">
    Inspect structured `412` responses for failed append preconditions.
  </Card>
</CardGroup>
