Skip to content

DBOS Instance support#291

Merged
devhawk merged 19 commits intomainfrom
devhawk/dbos-instance
Mar 6, 2026
Merged

DBOS Instance support#291
devhawk merged 19 commits intomainfrom
devhawk/dbos-instance

Conversation

@devhawk
Copy link
Collaborator

@devhawk devhawk commented Feb 28, 2026

ensures DBOS.Instance is usable and that all DBOS statics use the global DBOS instance.

  • DBOS.Instance is publicly constructable.
    • DBOS.Instance.setConfig removed - config is passed to the ctor
  • added a DBOS.Instance parameter to DBOSLifecycleListener.launch
  • updated DBOS internals to use DBOS.Instance instead of DBOS statics
    • changed WorkflowHandleFuture and WorkflowHandleDBPoll to use an executor instance
    • Added ClientWorkflowHandle that uses a sys db instance
  • DBOS.globalInstance is now an AtomicReference, eliminating the need for syncronized methods to set it
  • DBOS.configure sets the global instance if it is not null
  • DBOS.reinitialize unconditionally sets the global instance. This method is now package private as it is primarily intended for our test usage
  • DBOS static methods all forward to the global instance.
    • The global instance is NOT created on demand. If it is not set via DBOS.configure (or reinitialize) the static methods fail
  • Migrations are run on launch instead of when calling DBOS.configure
  • hard coded internal queue support in queue registry to eliminate need to register internal queue
  • minor cleanups (registerQueue no longer returns the queue, registerWorkflowMethod no longer returns the method's name)
  • added JavaDocs to all the DBOS.Instance public methods

Note: currently, there's no DBOS.Instance mechanism for something like using DBOS.startWorkflow to start a child workflow. Opened #296 to track fixing this.

@devhawk devhawk marked this pull request as ready for review March 4, 2026 23:22
@devhawk devhawk requested review from Copilot, kraftp, maxdml and qianl15 March 4, 2026 23:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class DBOS.Instance support and refactors DBOS internals/tests so static DBOS APIs forward to a configured global instance rather than relying on implicit singleton creation. This aligns the codebase toward explicit instance usage (and better multi-instance/test isolation), while keeping the static surface as a thin forwarding layer.

Changes:

  • Introduces/expands DBOS.Instance (constructor-based config, instance-forwarded APIs, migrations on launch).
  • Updates lifecycle listeners and workflow handle implementations to use an executor/instance rather than DBOS statics.
  • Refactors tests to use DBOSTestAccess.reinitialize(...) and adds a new InstanceTest validating direct instance usage.

Reviewed changes

Copilot reviewed 45 out of 45 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
transact/src/test/java/dev/dbos/transact/workflow/WorkflowMgmtTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/UnifiedProxyTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/TimeoutTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/SyncWorkflowTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/QueueChildWorkflowTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/ListWorkflowsTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/GarbageCollectionTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/ForkTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/workflow/AsyncWorkflowTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/step/StepsTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/scheduled/SchedulerServiceTest.java Adjusts test restart behavior to use DBOS.shutdown()/DBOS.launch().
transact/src/test/java/dev/dbos/transact/queue/QueuesTest.java Switches test reinit to DBOSTestAccess.reinitialize (including listen-queue test).
transact/src/test/java/dev/dbos/transact/queue/PartitionedQueuesTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/notifications/NotificationServiceTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/notifications/EventsTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/json/PortableSerializationTest.java Switches test reinit to DBOSTestAccess.reinitialize across serializer phases.
transact/src/test/java/dev/dbos/transact/json/InteropTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/issues/Issue218.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/invocation/StartWorkflowTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/invocation/PatchTest.java Switches test reinit to DBOSTestAccess.reinitialize across restart phases.
transact/src/test/java/dev/dbos/transact/invocation/MultiInstTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/invocation/InstanceTest.java New test suite covering direct DBOS.Instance usage patterns.
transact/src/test/java/dev/dbos/transact/invocation/DirectInvocationTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/invocation/CustomSchemaTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/execution/SingleExecutionTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/execution/ScaleTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/execution/RecoveryServiceTest.java Switches test reinit to DBOSTestAccess.reinitialize (including restart).
transact/src/test/java/dev/dbos/transact/execution/LifecycleTest.java Updates lifecycle callback signature to accept DBOS.Instance and uses instance methods.
transact/src/test/java/dev/dbos/transact/execution/DBOSExecutorTest.java Replaces registry clear/restart with reinitialize(config) flow.
transact/src/test/java/dev/dbos/transact/database/MetricsTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/config/ConfigTest.java Switches test reinit to DBOSTestAccess.reinitialize across config cases.
transact/src/test/java/dev/dbos/transact/client/PgSqlClientTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/client/ClientTest.java Switches test reinit to DBOSTestAccess.reinitialize.
transact/src/test/java/dev/dbos/transact/DBOSTestAccess.java Adds helpers for reinit and executor access under new instance model.
transact/src/main/kotlin/dev/dbos/transact/DBOSExtensions.kt Aligns Kotlin extension return type with new registerQueue signature.
transact/src/main/java/dev/dbos/transact/workflow/internal/WorkflowHandleFuture.java Uses executor instance for status rather than DBOS statics; makes fields final.
transact/src/main/java/dev/dbos/transact/workflow/internal/WorkflowHandleDBPoll.java Uses executor instance for status/result rather than DBOS statics.
transact/src/main/java/dev/dbos/transact/internal/QueueRegistry.java Adds reserved internal queue handling without needing registration.
transact/src/main/java/dev/dbos/transact/execution/SchedulerService.java Refactors to use injected DBOS.Instance in lifecycle callback.
transact/src/main/java/dev/dbos/transact/execution/DBOSLifecycleListener.java Updates lifecycle callback signature to accept DBOS.Instance.
transact/src/main/java/dev/dbos/transact/execution/DBOSExecutor.java Passes instance to listeners; refactors enqueue path to return workflowId and build handles with executor.
transact/src/main/java/dev/dbos/transact/database/WorkflowDAO.java Handles null authenticatedRoles when serializing forked workflow status.
transact/src/main/java/dev/dbos/transact/context/DBOSContext.java Exposes context serialization strategy accessor.
transact/src/main/java/dev/dbos/transact/DBOSClient.java Adds a client-side workflow handle implementation (sysdb-backed) and adapts to enqueue returning workflowId.
transact/src/main/java/dev/dbos/transact/DBOS.java Implements atomic global instance model; makes statics forward to global instance; moves migrations to launch; adds/updates instance APIs and JavaDocs.
Comments suppressed due to low confidence (1)

transact/src/main/java/dev/dbos/transact/execution/SchedulerService.java:79

  • In dbosShutDown(), this.dbos is set to null before shutting down the scheduler. Any scheduled task that is already running (or races with shutdown) can still call getLastTime/setLastTime and NPE on dbos. Set dbos to null only after the executor is stopped (or capture a local DBOS.Instance inside tasks / guard against null) to avoid shutdown-time NPEs.
  public void dbosShutDown() {
    this.dbos = null;
    var scheduler = this.scheduler.getAndSet(null);
    if (scheduler != null) {
      List<Runnable> notRun = scheduler.shutdownNow();
      logger.debug("Shutting down scheduler service. Tasks not run {}", notRun.size());
    }

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

Copy link
Member

@kraftp kraftp left a comment

Choose a reason for hiding this comment

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

To make sure I understand this, how does this change (if at all) how DBOS Java is used? Can you use it from an instance you create instead of from the global static?

@devhawk
Copy link
Collaborator Author

devhawk commented Mar 4, 2026

To make sure I understand this, how does this change (if at all) how DBOS Java is used? Can you use it from an instance you create instead of from the global static?

Yes, take a look at the new InstanceTest file. The vast, vast majority of the other test changes are using DBOSTestAccess to invoke DBOS.reinitialize static method. Since that method is for test usage, I made it package private

Copy link
Member

@kraftp kraftp left a comment

Choose a reason for hiding this comment

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

This makes sense. Having to pass the instance around is annoying, but unavoidable, and like you said there are ways to improve it in the future. And this will still be optional, you can still use the static if you want?

What I don't understand is if the instance remains a singleton, and what happens if you try to create multiple.

Also we should probably do a quick test mocking the instance, to verify it works as we expect as that's one of the main use cases for this feature.

@devhawk
Copy link
Collaborator Author

devhawk commented Mar 5, 2026

This makes sense. Having to pass the instance around is annoying, but unavoidable, and like you said there are ways to improve it in the future. And this will still be optional, you can still use the static if you want?

Yes, you can still use the statics if you want. Other than making reinitalize package private, none of the existing tests were changed.

What I don't understand is if the instance remains a singleton, and what happens if you try to create multiple.

The instance is not a singleton on its own. I will add a test creating multiples

Also we should probably do a quick test mocking the instance, to verify it works as we expect as that's one of the main use cases for this feature.

I'll add a test for this too

@devhawk devhawk force-pushed the devhawk/dbos-instance branch from c343caf to d25333f Compare March 5, 2026 17:31
@devhawk devhawk requested review from Copilot and kraftp March 5, 2026 22:40
Copy link
Contributor

Copilot AI left a comment

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 50 out of 50 changed files in this pull request and generated 10 comments.


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

@devhawk devhawk requested a review from Copilot March 5, 2026 22:45
Copy link
Contributor

Copilot AI left a comment

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 50 out of 50 changed files in this pull request and generated 4 comments.


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

Copy link
Member

@kraftp kraftp left a comment

Choose a reason for hiding this comment

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

This looks good! The new tests show that instances are working right for things like mocking, where we expect them to be used.

Documenting this will be tricky though. We'll probably want a dedicated testing guide, like https://docs.dbos.dev/typescript/tutorials/testing

@devhawk devhawk merged commit 92c574f into main Mar 6, 2026
41 of 42 checks passed
@devhawk devhawk deleted the devhawk/dbos-instance branch March 6, 2026 15:09
devhawk added a commit that referenced this pull request Mar 6, 2026
reverts a breaking change from #291 where DBOS.config was void return
instead of returning the global instance.

I think we should be keeping DBOS static and instnace APIs distinct, so
returning the global instance from the static configure method seems
wrong. However, this breaks a bunch of internal tests. So reverting
until we understand the problem better is the right choice. Opened #299
to track fixing this
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.

3 participants