Skip to content

Conversation

@maxdml
Copy link
Collaborator

@maxdml maxdml commented Jul 22, 2025

Builder pattern for the DBOS singleton:

  • Split building the object and launching
  • Stop exposing internal variables
  • Make app name & db url mandatory to init DBOS. This means using a config struct rather than functional options.

Manipulating the singleton object

package main

import (
	"context"
	"fmt"
	"os"

	"github.com/dbos-inc/dbos-transact-go/dbos"
)

var (
	wf = dbos.WithWorkflow(workflow)
)

func workflow(ctx context.Context, input string) (string, error) {
	return input, nil
}

func main() {
	err := dbos.Initialize(dbos.Config{
		AppName:     "dbos-hello",
		DatabaseURL: os.Getenv("DBOS_SYSTEM_DATABASE_URL"),
	})
	if err != nil {
		panic(err)
	}

	err = dbos.Launch()
	if err != nil {
		panic(err)
	}

	r, err := wf(context.Background(), "Hello, DBOS!")
	if err != nil {
		panic(err)
	}
	fmt.Println(r)

	dbos.Shutdown()
}

If a user needs to pass the DBOS singleton around and mock it, they can create a mock interface and write mocks manually or generate them with something like mockery.

What is public

  • Config
  • WorkflowStatus, Workflow Status types (e.g., dbos.WorkflowStatusPending)
  • The WorkflowHandle interface (concrete internal types: workflowHandle and workflowPollingHandle)
  • WithWorkflow wrapper, its functional options, and the returned WorkflowWrapperFunc (not sure whether the latter is actually useful to a user)
  • WorkflowFunc and StepFunc so users know what they can wrap
  • Single methods (Send, Recv, RetrieveWorkflow)
  • Input types for single methods like Send (WorkflowSendInput)
  • Error types
  • Queues: WorkflowQueue, NewWorkflowQueue, function options
  • SystemDatabase: I think it'll be useful to eventually allow users to inject a non-pg implementation (e.g., a mock) for testing.
  • StepInfo

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.

First thought--this is extremely messy. It's not at all obvious what methods are on the object and what are on the global. If you're going to expose the singleton, the "principled" thing to do is to put all methods on it, but that's syntactically a disaster (you'll have to push the singleton around through everything). Much cleaner to have all methods on the global, but then don't expose the singleton at all. We had this exact same debate in Python and decided on putting everything on the global.

@maxdml
Copy link
Collaborator Author

maxdml commented Jul 22, 2025

First thought--this is extremely messy. It's not at all obvious what methods are on the object and what are on the global. If you're going to expose the singleton, the "principled" thing to do is to put all methods on it, but that's syntactically a disaster (you'll have to push the singleton around through everything). Much cleaner to have all methods on the global, but then don't expose the singleton at all. We had this exact same debate in Python and decided on putting everything on the global.

I'm fine with this, the only benefit of exposing the singleton is to allow users to mock it in their program. But we can provide a similar benefit by allowing injection of the real thing that needs mocking: the system database.

@kraftp
Copy link
Member

kraftp commented Jul 22, 2025

First thought--this is extremely messy. It's not at all obvious what methods are on the object and what are on the global. If you're going to expose the singleton, the "principled" thing to do is to put all methods on it, but that's syntactically a disaster (you'll have to push the singleton around through everything). Much cleaner to have all methods on the global, but then don't expose the singleton at all. We had this exact same debate in Python and decided on putting everything on the global.

I'm fine with this, the only benefit of exposing the singleton is to allow users to mock it in their program. But we can provide a similar benefit by allowing injection of the real thing that needs mocking: the system database.

Sure, let's try that and see if we can make it robust + usable, it's sounds good in theory but not obvious at all where the mocks would come from.

@maxdml maxdml marked this pull request as ready for review July 22, 2025 22:42
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.

The change to the interface for Initialize/Launch looks good. If there are other significant changes, I can't find them through all the refactoring.

@maxdml
Copy link
Collaborator Author

maxdml commented Jul 22, 2025

The change to the interface for Initialize/Launch looks good. If there are other significant changes, I can't find them through all the refactoring.

Those two things:

  • app db and DB url are mandatory to the config
  • Executor config is now a config params object rather than functional options (not much value of the latter when there are mandatory parameters)

@maxdml maxdml changed the title WIP update scopes + DBOSExecutor singleton update scopes + DBOSExecutor singleton Jul 22, 2025
@maxdml maxdml merged commit 95f06a8 into main Jul 22, 2025
2 checks passed
@maxdml maxdml deleted the cleanup-interface branch July 22, 2025 23:44
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