Asynchronous API contracts
Cotani async methods return CompletionStage<T> or TaskChain<T> and never require callers to block for a result.
Thread boundaries
- Inputs are validated on the calling thread before work is scheduled.
- Storage, file and other blocking I/O executes on the explicit executor owned by the module.
- A completion stage may complete on that worker executor. It does not imply a Paper main, region or entity thread.
- Use
TaskChain.consumeGlobal,consumeRegionorconsumeEntitybefore accessing Bukkit/Paper state. - Capture
UUID, primitive values, records and immutable collection snapshots before leaving a server-owned thread. Do not retain livePlayer,World,Entity,InventoryorBlockreferences in async callbacks.
Failure, timeout and cancellation
- Validation failures documented as synchronous may be thrown before a stage is returned.
- I/O and domain failures complete the returned stage exceptionally. Completion wrappers such as
CompletionExceptionmay contain the domain cause. TaskChain.timeoutcompletes the chain exceptionally; it cannot guarantee interruption of an external operation that ignores cancellation.- Cancellation is best effort and propagates to Cotani-owned scheduled work. A remote database or Paper future may already have committed its side effect.
- Retry is accepted only for repeatable chains and must be limited to idempotent operations.
Lifecycle
- After
closeAsync()begins, a module rejects new work unless its API explicitly documents a different behavior. - Concurrent close calls coalesce where the API exposes
closeAsync(). - Observe the returned close stage and log failures. Never call blocking
close(),join()orget()on a Paper-owned thread.
The compile-checked examples in docs-examples exercise these boundaries during every build.