Skip to content

High Availability mode for Designer - #9416

Open
mateuszkp96 wants to merge 16 commits into
stagingfrom
feature/ha-designer
Open

High Availability mode for Designer#9416
mateuszkp96 wants to merge 16 commits into
stagingfrom
feature/ha-designer

Conversation

@mateuszkp96

Copy link
Copy Markdown
Contributor

Describe your changes

Checklist before merge

  • Related issue ID is placed at the beginning of PR title in [brackets] (can be GH issue or Nu Jira issue)
  • Code is cleaned from temporary changes and commented out lines
  • Parts of the code that are not easy to understand are documented in the code
  • Changes are covered by automated tests
  • Showcase in dev-application.conf added to demonstrate the feature
  • Documentation added or updated
  • Added entry in Changelog.md describing the change from the perspective of a public distribution user
  • Added MigrationGuide.md entry in the appropriate subcategory if introducing a breaking change
  • Verify that PR will be squashed during merge

@github-actions github-actions Bot added the docs label Jul 20, 2026
@mateuszkp96
mateuszkp96 marked this pull request as draft July 20, 2026 06:56
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

🟢 Cypress snapshots are up to date. No changes needed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a High Availability (HA) mode for the Designer backend, enabling multiple instances to run concurrently with leader-elected, single-instance execution of coordinated/background operations (via DB-backed distributed locks). It also adds a public endpoint to expose leader status for load balancers and documents the feature.

Changes:

  • Add DB-backed distributed locking + leader election services (PostgreSQL-only) and wire them into Designer startup and schedulers.
  • Gate background/periodic work (deployments reconciliation/synchronization and periodic deployment/rescheduling actors) behind leadership/locks.
  • Add GET /api/app/leader public endpoint, plus OpenAPI + migration guide/changelog updates and integration tests.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
scalafix-rules/src/test/scala/utils/SchemaInSqlDetectorSpec.scala Extends detector test coverage with SQL patterns used by distributed locks.
scalafix-rules/src/main/scala/utils/SchemaInSqlDetector.scala Updates SQL token heuristics to reduce false positives for new lock SQL constructs.
docs/MigrationGuide.md Documents the new optional ha { ... } configuration block and constraints.
docs/Changelog.md Adds changelog entry describing HA mode and the new leader endpoint.
docs-internal/api/nu-designer-openapi.yaml Documents /api/app/leader and its response schema in OpenAPI.
designer/server/src/test/scala/pl/touk/nussknacker/ui/process/periodic/flink/RescheduleFinishedActorTest.scala Updates actor tests to include periodic locking behavior (skip when lock not acquired).
designer/server/src/test/scala/pl/touk/nussknacker/ui/process/periodic/flink/DeploymentActorTest.scala Updates deployment actor tests for lock acquisition/renewal and in-flight behavior.
designer/server/src/test/scala/pl/touk/nussknacker/ui/ha/SlickDistributedLockSpec.scala Adds Postgres-backed tests for acquire/renew/release semantics.
designer/server/src/test/scala/pl/touk/nussknacker/ui/ha/LeadershipServiceSpec.scala Adds unit tests for leader election heartbeat, callbacks, and stop behavior.
designer/server/src/test/scala/pl/touk/nussknacker/ui/api/AppApiHttpServiceHaSpec.scala Adds IT coverage for /api/app/leader in HA-enabled mode using Postgres DB.
designer/server/src/test/scala/pl/touk/nussknacker/ui/api/AppApiHttpServiceBusinessSpec.scala Adds test for /api/app/leader when HA is disabled (no instanceId).
designer/server/src/test/scala/pl/touk/nussknacker/test/base/it/NuItTestWithPostgres.scala Introduces an IT base trait that starts the app with Postgres for HA endpoint testing.
designer/server/src/main/scala/pl/touk/nussknacker/ui/server/TapirHttpServiceFactory.scala Wires Leadership into AppApiHttpService.
designer/server/src/main/scala/pl/touk/nussknacker/ui/process/periodic/SchedulingDependencies.scala Threads PeriodicLock through periodic scheduling dependencies.
designer/server/src/main/scala/pl/touk/nussknacker/ui/process/periodic/RescheduleFinishedActor.scala Adds periodic lock acquisition before rescheduling/marking failures.
designer/server/src/main/scala/pl/touk/nussknacker/ui/process/periodic/PeriodicLock.scala Introduces a shared periodic-work lock wrapper with HA-aware resource lifecycle.
designer/server/src/main/scala/pl/touk/nussknacker/ui/process/periodic/PeriodicDeploymentManager.scala Uses PeriodicLock when creating periodic actors.
designer/server/src/main/scala/pl/touk/nussknacker/ui/process/periodic/DeploymentActor.scala Adds lock acquisition/renewal logic to periodic deployments to avoid multi-instance duplication.
designer/server/src/main/scala/pl/touk/nussknacker/ui/process/newdeployment/synchronize/DeploymentsStatusesSynchronizationScheduler.scala Runs deployment status synchronization only on the elected leader.
designer/server/src/main/scala/pl/touk/nussknacker/ui/process/deployment/reconciliation/FinishedDeploymentsStatusesSynchronizationScheduler.scala Runs finished-deployments reconciliation only on the elected leader.
designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Adds leader election service with heartbeat + callbacks + shutdown handling.
designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/LeaderLock.scala Adds a dedicated leader lock wrapper (name + acquire/renew/release).
designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/HaMode.scala Adds HA config parsing + validation (durations/constraints).
designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/DistributedLock.scala Implements Slick/Postgres distributed lock operations and NoOp fallback.
designer/server/src/main/scala/pl/touk/nussknacker/ui/factory/NussknackerAppFactory.scala Triggers recovery on leadership acquisition (not only at startup).
designer/server/src/main/scala/pl/touk/nussknacker/ui/factory/DomainServices.scala Creates/wires DistributedLock, PeriodicLock, and Leadership into domain services and schedulers.
designer/server/src/main/scala/pl/touk/nussknacker/ui/config/DesignerConfig.scala Adds haMode to resolved DesignerConfig.
designer/server/src/main/scala/pl/touk/nussknacker/ui/api/description/AppApiEndpoints.scala Adds Tapir endpoint + DTO/encoder for leader status response.
designer/server/src/main/scala/pl/touk/nussknacker/ui/api/AppApiHttpService.scala Exposes /api/app/leader and returns leader status + instanceId.
designer/server/src/main/resources/db/migration/postgres/V1_072__DistributedLocksTable.sql Adds Postgres migration creating distributed_locks table.
designer/server/src/main/resources/db/migration/hsql/V1_072__DistributedLocksTable.sql Adds HSQL no-op migration with explanation (HA requires Postgres).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/DistributedLock.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
@mateuszkp96
mateuszkp96 marked this pull request as ready for review July 21, 2026 08:23
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/HaMode.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/api/AppApiHttpService.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/LeaderLock.scala Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

designer/server/src/test/scala/pl/touk/nussknacker/ui/ha/SlickDistributedLockSpec.scala:81

  • The Using(...) result is ignored here as well, which would hide failures inserting the expired lock and potentially make the test pass for the wrong reason. Append .get so a failed INSERT fails the test.
    Using(testDbRef.db.createSession()) { session =>
      session
        .prepareStatement(
          s"""INSERT INTO "${getSchemaName()}".distributed_locks (name, lock_until, locked_at, locked_by)
             |VALUES ('$lockName', CURRENT_TIMESTAMP - INTERVAL '1 second', CURRENT_TIMESTAMP - INTERVAL '60 seconds', '$holder')""".stripMargin
        )
        .execute()
    }

designer/server/src/test/scala/pl/touk/nussknacker/ui/ha/SlickDistributedLockSpec.scala:23

  • The Using(...) result is ignored, so if the TRUNCATE fails the exception will be swallowed and the test may continue with dirty state. Call .get (or otherwise rethrow) to ensure DB cleanup failures fail the test.

This issue also appears on line 74 of the same file.

    Using(testDbRef.db.createSession()) { session =>
      session.prepareStatement(s"""TRUNCATE TABLE "${getSchemaName()}".distributed_locks""").execute()
    }

Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/HaMode.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/DistributedLock.scala Outdated
Comment thread scalafix-rules/src/test/scala/utils/SchemaInSqlDetectorSpec.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/DistributedLock.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/Leadership.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/HaMode.scala Outdated
Comment thread designer/server/src/main/scala/pl/touk/nussknacker/ui/ha/DistributedLock.scala Outdated
Comment thread docs/Changelog.md

### 1.19.0 (Not released yet)

* [#9416](https://github.com/TouK/nussknacker/pull/9416) Feature: High Availability (HA) mode for the Designer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HA mode's configuration should be described in documentation, along with new API endpoints

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants