Skip to content
Back to skills

Stateless Service Design

ASecurity

Making a service instance disposable so replicas are interchangeable: what stateless actually means — no correctness/routing dependency on one instance's volatile history; the in-process state inventory; and session state as a placement decision between sticky routing, an external store and a signed token. Use when replicas is raised above 1, when a @Scheduled job suddenly runs N times, when a local cache disagrees between instances, when an in-memory rate-limit counter or idempotency map is ...

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
developmentrustjavaspringkubernetesapidatabasesecurity

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 29, 2026

npx -y skills add robsonkades/agent-skills --skill stateless-service-design --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Stateless Service Design?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Stateless Service Design
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/robsonkades-stateless-service-design/badge)](https://www.skillsdirectory.com/skills/robsonkades-stateless-service-design)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: stateless-service-design
description: >
  Making a service instance disposable so replicas are interchangeable: what stateless
  actually means — no correctness/routing dependency on one instance's volatile history; the in-process state
  inventory; and session state as a placement decision between sticky routing, an external
  store and a signed token. Use when replicas is raised above 1, when a @Scheduled job
  suddenly runs N times, when a local cache disagrees between instances, when an in-memory
  rate-limit counter or idempotency map is the source of truth, when HttpSession holds
  anything a user would miss, when a service writes to java.io.tmpdir, or when a rolling
  deploy loses sessions. Does not cover pod replacement and drain
  (kubernetes-service-lifecycle), reaching a replica (load-balancing-and-routing), cache
  design (caching-strategies), fleet-singleton work (leader-election), state split by key
  (sharding-and-partitioning), pool arithmetic (connection-pool-sizing), or what replicas
  may observe (consistency-models).
---

# Stateless Service Design

## Purpose

Decide which state may stay instance-local and what replacement requires. “Stateless” does not
mean empty memory; it means request correctness/routing does not depend on a particular
instance's volatile history. Classify state by authority, durability, consistency scope,
reconstruction source/time and loss consequence. A local derivable cache can stay; a replicated
stateful actor/broker can also be correct, but it needs explicit ownership and recovery rather
than interchangeable stateless routing.

The failure this prevents is a hidden instance-ownership assumption. One-replica tests can
miss cross-replica divergence, but concurrency, duplicate registration and restart loss can
already fail within one instance. Adding capacity can expose further failures — a duplicate
charge, a fleet limit enforced separately on each replica, or repeated job effects.

## Workflow

Use the steps relevant to the question and reuse adequate existing evidence. A narrow
explanation or sound stateful/session-loss contract need not trigger a complete inventory,
new authority, migration or full fault/deployment campaign. Keep unknown guarantees explicit.

1. **Apply loss, divergence and recovery tests.** If this JVM disappears, what correctness,
   accepted work, security decision, user journey or SLO changes? Can another instance rebuild
   from durable truth within RTO/RPO, and can copies diverge? Authoritative state may move to a
   shared store or become partitioned/replicated state with an explicit owner.
2. **Inventory the affected state before redesign.** Inspect singleton bean fields, `static` collections,
   `HttpSession` attributes, caches, scheduler and executor queues, local files and
   long-lived connections; identify derivation, lifetime and decision authority separately. The
   table and the grep shapes are in `references/state-inventory.md`.
3. **Place session state deliberately.** Sticky routing, an external session store and a
   signed token are three different failure and revocation profiles, not three flavours of
   one idea. See `references/session-placement.md`.
4. **Name the existing or proposed authority and guarantee**—database row, durable queue/outbox, replicated
   partition or client token. Product labels do not decide semantics: Redis can be a cache or
   configured data store; verify eviction, persistence, replication, consistency, backup and
   failover before assigning authority.
5. **Hunt singleton assumptions.** Inspect enabled schedule registrations, bean instances and
   startup hooks in each application context. Fleet-once work needs partitioning, a scheduler with documented coordination, or
   `leader-election`; TTL leases, session locks and durable job claims have different stale-
   owner/recovery semantics.
6. **Verify the claimed transition.** For cross-replica or replacement guarantees, route named steps deliberately to different instances
   (random balancing may miss the transition), overlap relevant requests and test replacement
   during the affected work/deployment phases. Reuse adequate evidence. A green run at
   `replicas: 1` does not establish cross-replica correctness. Fault injection belongs in an
   isolated or already authorized environment; successful cases cover only the paths exercised.
7. **Check relevant shared capacity when changing replication.** Replication can move the bottleneck to what
   the replicas share. `replicas × maximumPoolSize` is a number the database has an opinion
   about; that arithmetic is `connection-pool-sizing`.

## Decision block

```text
Make the instance stateless and scale by replication when:
- each request's required inputs are available to eligible instances, from the request,
  validated client state and/or shared authority, within the workload and trust contract
- where writes exist, eligible instances can satisfy the required ownership and ordering
  protocol without depending on one instance's volatile history
Keep the state in the process when:
- it is derivable and freshness, loss and rebuild costs fit the contract, including
  availability, upstream quotas and recovery load (a cache)
- its lifetime is one request (a transaction, a request-scoped bean, a ScopedValue binding)
Consider partitioning by key (sharding-and-partitioning) when:
- the per-key working set is too large or too hot to load per request, or the key needs
  single-writer ordering that shared storage would otherwise have to serialise
Prefer leader election (leader-election) instead when:
- the work must happen once per interval across the fleet rather than once per instance
  (election coordinates ownership; durable claims/idempotent effects are still needed where
  retries, failover or stale owners can repeat work)
```

## Rules

- Identify which copy owns the decision and can recover it. A field's size or lifetime does
  not establish authority; inspect loss, divergence and recovery together, including caches
  that temporarily influence security or correctness.
- Mutable `static` state on the request path needs a scope and authority check. Local metrics,
  protective limits and derivable caches can be valid; a local source of truth for a fleet-wide
  decision is unsafe. Inspect readers, writers, thread safety and divergence consequences.
- An uncoordinated in-process counter that gates a fleet-wide business decision enforces a
  separate budget per instance. Maximum aggregate allowance can approach N× under spread,
  though routing/skew changes observed behavior. Per-instance protective limits are valid when
  explicitly scoped (`rate-limiting-and-load-shedding`).
- Spring scheduling is local to enabled application contexts. Count bean instances and
  schedule declarations: Spring 6.2.12 processes repeated `@Scheduled` declarations independently,
  and multiple bean instances can each register callbacks. Replica count alone does not determine
  invocation or effect count; an outer scheduler/claim/lease or repeat-safe work changes the contract.
- An in-memory idempotency map can deduplicate only within its instance and retention window,
  with an atomic local claim when attempts overlap. Cross-replica/restart guarantees need a protocol covering
  the actual effects: natural idempotence, or an atomic claim and effect/recovery protocol such
  as a durable unique-key record where required; `idempotency`
  owns the mechanics, this skill owns noticing that the map was never shared.
- A local cache can diverge after update/invalidation for its refresh/eviction/restart horizon;
  no TTL makes staleness unbounded unless explicit invalidation or replacement succeeds, not
  mathematically permanent. Cache design is
  `caching-strategies`; the multi-replica consequence is here.
- Trace local paths to actual mounts. Container writable layers can be lost on container
  replacement; `emptyDir` survives container restarts but ends with the Pod; persistent volumes
  have separate retention and access rules. Durability alone does not make a file reachable
  from another replica. A staged upload referenced by a later request needs that contract.
- `HttpSession` is in-process state by default. Anything in it a user would notice losing —
  cart contents, a multi-step form, an authorisation decision — needs a loss/staleness policy;
  it may be authoritative or reconstructible from another authority. Spring
  Session changes the store without changing the servlet API: a placement change, not a
  rewrite. Shared placement does not make overlapping session read-modify-write operations
  atomic; verify conflict handling across eligible instances (`session-state-strategies`).
- **Sticky sessions give affinity, not a guarantee.** Affinity ends when the replica dies,
  when a rolling update drains it, when the client drops the cookie, or when the balancer's
  table is rebuilt. Each of those is user-visible if the state existed only there.
- A signed token moves claims to the client; signing provides integrity/authenticity, not
  confidentiality. Short expiry bounds token lifetime; revocation before expiry needs a
  verifier-enforced mechanism such as introspection, denylist/session version, or key/policy
  changes—each trades latency,
  blast radius and freshness. JWT is a format, not a session architecture.
- A WebSocket, SSE stream or long poll pins one user to one instance for the connection's
  lifetime. Pushing to that user from another replica needs a broker or a fan-out, and a
  replacing instance can terminate its streams. Clients need bounded reconnect and a
  cursor/replay or snapshot protocol when missed events affect correctness.
- Do not claim statelessness because a class has no fields. State hides in the framework
  too: session attributes, a `ThreadLocal` never cleared, a filter's cache, a library's
  static registry. Use the inventory and targeted failure evidence; code shape alone does not.

## Stateful is not a defect

Prefer explicit stateful ownership when locality, single-writer order or working-set cost
requires it. Then specify partition placement, replication/quorum, durable log/snapshot,
ownership epochs/fencing, failover/rebalance and backup/restore. Calling that service stateless
because an orchestrator can restart it erases its hardest contract.

## Security and shutdown

Inspect deployed Java, Spring/Session/Data Redis versions, storage mounts and routing before
changing placement. No upgrade is implied; ScopedValue is final in Java 25 and preview/incubator
in earlier supported releases. Missing recovery or durability evidence is unknown. Deliver the
supported conclusion, relevant authority/loss contract, checks performed and material gaps;
include an affected-state inventory when the requested audit or change needs one.

- Refuse protected actions when required session/auth evidence is unavailable or too stale.
  Independently sufficient local token validation or a still-valid cached decision may remain
  usable under the existing policy; a store outage does not authorize weakening that policy.
  Never replace required live revocation/introspection with signature-only validation, extend
  an expired decision, or reinterpret unknown authentication as authenticated. Optional
  personalization can degrade separately from the authority required for access.
- For replacement, stop admission and preserve the promised acceptance contract: finish or
  durably hand off/replay accepted queues/uploads before termination, with bounded drain and
  recovery. Explicit best-effort loss is a different contract. “No fields” does not prevent loss
  of in-flight accepted work.
- Bind token/session to issuer, audience, tenant and key version; protect against fixation,
  replay, key rotation overlap and cross-tenant cache keys.

## References

- [In-process state inventory](references/state-inventory.md) — common in-process state,
  authority/lifetime distinctions, potential failures, discovery shapes and placement options.
  Read when auditing a service before scaling it
  out, or when a bug appears on some replicas and not others.
- [Where session state lives](references/session-placement.md) — sticky routing, an external
  store and a signed token compared on replica-death behaviour, deploy behaviour, per-request
  latency and revocation, with the Spring Session and token shapes and a decision block.
  Read when the service holds a session, or when a deploy logs users out.
  For detailed per-item conversation placement, use `session-state-strategies`.

Files in this skill

  • SKILL.md11.8 KB
  • references/session-placement.md11.1 KB
  • references/state-inventory.md10.6 KB
  • skill.yaml2.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.