Skip to content

Operational constraints and troubleshooting

Required invariants

  • Write a complete candidate snapshot before calling release().
  • Use one explicit root manager when a scope contains several managers.
  • Register every dependency manager that must participate in garbage collection.
  • Include buildStrate in every relation mapping between stratified tables.
  • Preserve foreign-key dependency order even when independent branches are executed concurrently.
  • Keep the build and release metadata managers on the same database connection.
  • Treat released_strates as the only source of truth for the active snapshot.
  • Do not add a duplicated released flag to every business row.
  • Do not call release() until all required persistence branches have completed successfully.

Concurrency and connection pools

Snapshot isolation makes application-level parallel persistence possible, but concurrency still consumes database resources.

When parallelizing independent graph branches:

  • size concurrency to the available connection pool rather than spawning unbounded coroutines;
  • keep transactions local to the branch that requires them;
  • expect foreign-key and unique-index contention to serialize conflicting writes;
  • propagate a failure from any required branch and do not release the build;
  • mark abandoned candidates as failed when appropriate;
  • measure the database critical path rather than assuming more workers always improve throughput.

persistMany() itself is sequential. Strates provides the isolation boundary that lets the caller safely coordinate several persistence tasks against the same unreleased buildStrate.

Common exceptions

UnknownStratesScopeException
The scope was not supplied in the constructor configuration.
InvalidStratifiedEntityException
A manager lacks id, buildStrate or the configured scope-id field, or its entity does not implement StratifiedEntityInterface.
BuildNotFoundException
No build matches the supplied scope, scope id and strate.
UnsupportedDatabaseTypeException
Partition garbage collection received a connection other than the supported MySQL or PostgreSQL drivers.
RuntimeException during release
The build status is neither building nor released.
LogicException during release
The stratified build and release metadata managers do not use the same connection instance.

PostgreSQL Core 3.0 release path

Core 3.0 PersistThread::commit() obtains a native driver connection and only provides a real transaction when that driver exposes PDO-style beginTransaction() and commit() methods.

The native PostgreSQL driver uses PgSql\Connection, so that condition is not met. Core therefore falls back to flush() after checking out the driver connection. Strates deliberately uses flush() directly for PostgreSQL release metadata, avoiding the unnecessary checkout while preserving the effective behavior of the Core 3.0 path.

Reader publication and database transaction are different guarantees

The release pointer remains the visibility source of truth, so readers switch from one completed snapshot to another through that pointer. The native PostgreSQL release metadata path must not be documented as a database transaction. Use explicit transaction-safe database logic if the application requires stronger metadata ACID guarantees than the current Core 3.0 native driver provides.

Test and quality matrix for Strates 1.0.0

The package integration suite covers MySQL and PostgreSQL relation graphs, including:

  • one-to-one, one-to-many and join-entity many-to-many relations;
  • composite relation mappings with buildStrate;
  • unreleased snapshot invisibility;
  • release-pointer switching and idempotent release;
  • scope-id isolation;
  • failed and mismatched build handling;
  • garbage collection across dependency managers;
  • superseded released builds with equal timestamps.

The release line is validated with PHP syntax checks, PHPStan level 9 and a 100% line-coverage gate.

Next chapter: Architecture, versioning and parallel persistence