Skip to main content

Lifecycle

SqlxBroker::from_url records configuration, connect builds the pool and resolves the dialect, each subscription prepares its SQL at startup, and shutdown stops the claims.

The broker's states as types, and what each transition does on the databaseBrokerOn the databaseSqlxBroker::from_url(..)ConnectedSqlxBrokerClosedSqlxBrokerlocks_released,connections_closedThe pool's settings,routes, lease: no I/OPool built; oneconnection taken, thedialect resolved; onemore for listen_notifyEach subscription:declaration checked,statements built,server version read,each one preparedClaim loops run;a keeper extends theleases each half leaseClaims and keepersstop; advisory locksreleased; the listenerand a built poolclosedA publisher that outlives the broker answersSqlxBrokerError::Closed, never a silent success
The diagram as text
  1. Broker: SqlxBroker ::from_url(..); ConnectedSqlx Broker; ClosedSqlxBroker locks_released, connections_closed
  2. On the database: The pool's settings, routes, lease: no I/O; Pool built; one connection taken, the dialect resolved; one more for listen_notify; Each subscription: declaration checked, statements built, server version read, each one prepared; Claim loops run; a keeper extends the leases each half lease; Claims and keepers stop; advisory locks released; the listener and a built pool closed
  3. SqlxBroker ::from_url(..) → ConnectedSqlx Broker: connect(self)
  4. ConnectedSqlx Broker → ClosedSqlxBroker locks_released, connections_closed: shutdown(self)
  5. The pool's settings, routes, lease: no I/O → Pool built; one connection taken, the dialect resolved; one more for listen_notify
  6. Pool built; one connection taken, the dialect resolved; one more for listen_notify → Each subscription: declaration checked, statements built, server version read, each one prepared
  7. Each subscription: declaration checked, statements built, server version read, each one prepared → Claim loops run; a keeper extends the leases each half lease
  8. Claim loops run; a keeper extends the leases each half lease → Claims and keepers stop; advisory locks released; the listener and a built pool closed
  9. A publisher that outlives the broker answers SqlxBrokerError::Closed, never a silent success

from_url, from_connect_options, route, poll_interval, lease, connection_limit and listen_notify do no I/O, so the service's builder stays synchronous and runs before the runtime starts. SqlxBroker::new takes a pool the service built itself, inside the runtime, and shares with code of its own.

Connect builds the pool from the recorded settings, then takes one connection of it, which checks that the database is reachable: a URL the driver cannot read fails the start with SqlxBrokerError::Url, and a database out of reach with SqlxBrokerError::Connect. On that connection the broker resolves its dialect, which matters for an AnyPool: it learns there which database it reaches. Then it gives the connection back. Under listen_notify it takes one more, which it keeps until shutdown to listen for notifications.

Each subscription opens in order. Its declaration is checked first: max_attempts without dead_letter, or the other way round, and a cap on a table without an attempt column, stop it with SqlxBrokerError::Declaration. Its statements are built from the table's description, and a second subscription to the same queue on this broker is refused. Then, on one connection, the dialect reads the server's version where it has a floor, as MySQL and MariaDB do, and every statement is prepared on the server: a table or a column the database lacks stops the service at startup with SqlxBrokerError::Schema, naming the table and the statement. Last, under listen_notify, the subscription listens on its table's channel. Every error at this point is an error of startup, before a message is claimed.

While the service runs, each subscription claims as Waking describes, and in the lease form a task of its own extends every lease in work each half lease.

Shutdown sets the broker's closed flag, which refuses every publisher handed out before, since a pool the service shares stays open. It stops the claim loops and the lease keepers. A delivery in work in the row lock or lease form settles as before: its transaction or its lease still holds the row, and a lease is no longer extended. In the advisory lock form shutdown releases the lock of every delivery in work, and a delivery whose lock it released settles no more: its settlement fails with Closed, and its row is back in the queue. A claim the runtime cut short when it stopped a subscription may still run on the server; its connection waits for the server to end the claim's statement and roll its transaction back, and then closes. Shutdown waits for those connections and for every session still closing, closes the listening connection and the pool it built, and returns ClosedSqlxBroker, which counts the locks released with their connections back in the pool and the connections closed instead.

Shutdown does not return claimed rows by itself. Each form returns them in its own way: the row lock form when its transaction rolls back or its connection closes, the lease form when a dropped delivery releases its lease or the lease runs out, the advisory lock form when its lock is released. In a service the runtime drains the handlers before it shuts the broker down, and a handler aborted at the drain timeout drops its delivery.