Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 30, 2026

Implements PostgreSQL as a first-class backend for lease-based distributed locks, consistent with existing backends (Firestore, etcd, DynamoDB, memory).

Changes

New locker-postgres module

  • PostgresLockService with atomic SQL operations using INSERT ... ON CONFLICT, UPDATE, DELETE with RETURNING
  • Composite primary key (namespace, lock_name) — no synthetic lock_id
  • All lock edge cases evaluated server-side via SQL WHERE conditions
  • Expiry checks use EXTRACT(EPOCH FROM now())::bigint for database-evaluated time
  • Table name validation to prevent SQL injection

Schema

CREATE TABLE locks (
    namespace VARCHAR(255) NOT NULL,
    lock_name VARCHAR(255) NOT NULL,
    owner VARCHAR(255) NOT NULL,
    instance_id VARCHAR(255) NOT NULL,
    lease_duration BIGINT NOT NULL,
    expiry BIGINT NOT NULL,
    PRIMARY KEY (namespace, lock_name)
);

Build integration

  • Maven postgres profile in root and api POMs
  • Added to everything profile for full builds
  • GitHub Actions workflow matrix includes postgres variant

Configuration

  • Spring @Profile("postgres") conditional activation
  • HikariCP connection pooling
  • Properties: locker.postgres.{host,port,database,schema,username,password,ssl,tableName}

Dependencies

  • PostgreSQL driver 42.7.7 (patched for channelBinding fallback vulnerability)
  • HikariCP 6.2.1
Original prompt

Add Postgres backend to LockServiceCentral

Implement a new Postgres backend for lease based distributed locks in UnitVectorY-Labs/LockServiceCentral, consistent with the existing backend modules (Firestore, etcd, DynamoDB, memory). The goal is to add Postgres as a first class backend option with the same external API behavior and the same conventions for module layout, config, build profiles, docs, and logging.

  1. Scope and shape
    • Add a new Maven module named something like locker-postgres/ following the same structure and conventions used by other backend modules.
    • Provide a Postgres LockService implementation wired through Spring configuration, mirroring how other backends are enabled.
    • Add a Postgres Maven profile at the root (and include it in any “build all” profile if one exists), following the pattern used by other backends.
    • Add the appropriate conditional to the API pom when the postgres profile is active
    • Ensure the main application can be built and packaged with Postgres selected the same way other backends are selected (Maven profile plus any existing Docker build-arg pattern if applicable).

  2. Database design and atomic lock semantics

Design the table and queries so that all lock correctness is enforced by Postgres, using atomic SQL statements and database evaluated conditions. Do not implement lock edge case handling by doing reads and then deciding what to write in application code.

Key properties that must be handled by SQL conditions, atomically:
• Acquire lock when no row exists.
• Acquire lock when an existing lock is expired.
• Acquire lock when the request is from the same owner and instance and should be treated as a safe re-acquire (mirror behavior from other backends).
• Renew lock only when the lock exists, is not expired at the time of renewal, and is owned by the same owner and instance.
• Release lock only when owned by the same owner and instance.
• Treat “release of a lock that does not exist” as a successful release if that matches current cross-backend behavior.

Implementation guidance:
• Avoid “read then write” patterns that allow races. Use one statement per operation where the WHERE or ON CONFLICT conditions encode all required edge cases and ownership checks.
• Prefer Postgres-native patterns like INSERT ... ON CONFLICT ... DO UPDATE ... WHERE ... RETURNING ... for acquire, and UPDATE ... WHERE ... RETURNING ... for renew, and DELETE ... WHERE ... RETURNING ... for release. Use RETURNING to distinguish conflict vs not-found outcomes without extra queries.
• Use database time consistently (for example Postgres now() or transaction_timestamp()), so comparisons against expiry are evaluated inside the statement, not computed client side.
• Make the lock identifier and uniqueness match existing backends (for example a single primary key derived from {namespace}:{lockName}) so behavior stays aligned.

  1. Configuration
    • Add Spring configuration properties for Postgres similar in style to other backends (host, port, database, schema, username/password, SSL options if applicable, table name if configurable).
    • Follow existing conventions for how configuration is documented and how defaults are handled.
    • Ensure credentials can be supplied via environment variables in the same spirit as other backends.

  2. Canonical logging and outcomes

Use the repository’s canonical logging approach consistently:
• Expected outcomes like acquire conflict, renew conflict, release conflict should not emit extra ad hoc debug log lines.
• Record outcomes in the canonical log context in the same way other backends do so each request produces one structured canonical log line and conflicts are represented as outcomes rather than extra logs. This is accomplished by using the logging library defined in this project, the intent is to avoid directly logging log lines.
• Only unexpected errors should be logged as errors, consistent with other implementations.

  1. Build and packaging changes

Make the repo build and CI aware of the new backend:
• Update the GitHub Actions workflow matrix that builds backend variants so Postgres is included alongside existing variants. 
• Update the api app POM (and any other required Maven wiring) so the Postgres backend is included only when the Postgres profile is selected, matching how other backends are conditionally included.
• If Docker build args are used to select backends, update the Docker build logic and any docs/examples so Postgres is selectable the same way.

  1. Documentation
    • Update the root README “Supported Backends” and build instructions to include Postgres as an option.
    • Add a module README under locker-postgres/ describing:
    • Required table schema and indexes
    • Configuration properties and examples
    • How expiry is represented and interpreted
    • A quick local development setup suggestion (for example a simple Postgres container setup)

  2. Testing approach

Focus on correctness of the implementation and ...


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 5 commits January 30, 2026 02:30
Co-authored-by: JaredHatfield <208119+JaredHatfield@users.noreply.github.com>
Co-authored-by: JaredHatfield <208119+JaredHatfield@users.noreply.github.com>
Co-authored-by: JaredHatfield <208119+JaredHatfield@users.noreply.github.com>
…name)

Co-authored-by: JaredHatfield <208119+JaredHatfield@users.noreply.github.com>
Co-authored-by: JaredHatfield <208119+JaredHatfield@users.noreply.github.com>
Copilot AI changed the title [WIP] Add Postgres backend to LockServiceCentral Add PostgreSQL backend for distributed locks Jan 30, 2026
Copilot AI requested a review from JaredHatfield January 30, 2026 02:47
@JaredHatfield JaredHatfield marked this pull request as ready for review January 30, 2026 10:46
@codecov
Copy link

codecov bot commented Jan 30, 2026

Codecov Report

❌ Patch coverage is 12.94964% with 121 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.67%. Comparing base (943c17a) to head (83405de).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
...cecentral/locker/postgres/PostgresLockService.java 16.21% 90 Missing and 3 partials ⚠️
...ocker/postgres/LockerPostgresDataSourceConfig.java 0.00% 26 Missing ⚠️
...ecentral/locker/postgres/LockerPostgresConfig.java 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #104      +/-   ##
============================================
- Coverage     38.75%   35.67%   -3.08%     
- Complexity      136      143       +7     
============================================
  Files            31       34       +3     
  Lines          1027     1166     +139     
  Branches        112      123      +11     
============================================
+ Hits            398      416      +18     
- Misses          600      718     +118     
- Partials         29       32       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@JaredHatfield JaredHatfield merged commit ac5cf54 into main Jan 30, 2026
3 of 5 checks passed
@JaredHatfield JaredHatfield deleted the copilot/add-postgres-backend-module branch January 30, 2026 22:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants