I have a backend process that maintains state in a PostgreSQL database, which needs to be visible to the frontend. I want to:
-
Properly handle the backend being stopped and started. This alone is as simple as clearing out the backend state tables on startup.
-
Guard against multiple instances of the backend trampling each other. There should only be one backend process, but if I accidentally start a second instance, I want to make sure either the first instance is killed, or the second instance is blocked until the first instance dies.
Solutions I can think of include:
-
Exploit the fact that my backend process listens on a port. If a second instance of the process tries to start, it will fail with “Address already in use”. I just have to make sure it does the
listenstep before connecting to the database and wiping out state tables. -
Open a secondary connection and run the following:
BEGIN; LOCK TABLE initech.backend_lock IN EXCLUSIVE MODE;Note: the reason for
IN EXCLUSIVE MODEis thatLOCKdefaults to the AccessExclusive locking mode. This conflicts with the AccessShare lock acquired bypg_dump.Don’t commit. Leave the table locked until the program dies.
What’s a good pattern for maintaining a singleton backend process that maintains state in a PostgreSQL database? Ideally, I would acquire a lock for the duration of the connection, but LOCK TABLE cannot be used outside of a transaction.
Background
Consider an application with a “broker” process which talks to the database, and accepts connections from clients. Any time a client connects, the broker process adds an entry for it to the database. This provides two benefits:
-
The frontend can query the database to see what clients are connected.
-
When a row changes in another table called
initech.objects, and clients need to know about it, I can create a trigger that generates a list of clients to notify of the change, writes it to a table, then uses NOTIFY to wake up the broker process.Without the table of connected clients, the application has to figure out what clients to notify. In my case, this turned out to be quite messy: store a copy of the
initech.objectstable in memory, and any time a row changes, dispatch the old row and new row to handlers that check if the row changed and act if it did. To do it efficiently involves creating “indexes” against both the table-stored-in-memory, and handlers interested in row changes. I’m making a poor replica of SQL’s indexing and querying capabilities in the broker program. I’d rather move this work to the database.
In summary, I want the broker process to maintain some of its state in the database. It vastly simplifies dispatching configuration changes to clients, but it requires that only one instance of the broker be connected to the database at a time.
it can be done by advisory locks
http://www.postgresql.org/docs/9.1/interactive/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS