55import dev .dbos .transact .context .DBOSContextHolder ;
66import dev .dbos .transact .database .ExternalState ;
77import dev .dbos .transact .execution .DBOSExecutor ;
8+ import dev .dbos .transact .execution .DBOSLifecycleListener ;
9+ import dev .dbos .transact .execution .RegisteredWorkflow ;
10+ import dev .dbos .transact .execution .RegisteredWorkflowInstance ;
811import dev .dbos .transact .execution .ThrowingRunnable ;
912import dev .dbos .transact .execution .ThrowingSupplier ;
1013import dev .dbos .transact .internal .DBOSInvocationHandler ;
1720
1821import java .lang .reflect .Method ;
1922import java .time .Duration ;
23+ import java .util .Collection ;
24+ import java .util .HashSet ;
2025import java .util .List ;
2126import java .util .Objects ;
2227import java .util .Optional ;
28+ import java .util .Set ;
29+ import java .util .concurrent .ConcurrentHashMap ;
2330import java .util .concurrent .atomic .AtomicReference ;
2431
2532import org .slf4j .Logger ;
@@ -38,6 +45,7 @@ private DBOS() {}
3845 public static class Instance {
3946 private final WorkflowRegistry workflowRegistry = new WorkflowRegistry ();
4047 private final QueueRegistry queueRegistry = new QueueRegistry ();
48+ private final Set <DBOSLifecycleListener > lifecycleRegistry = ConcurrentHashMap .newKeySet ();
4149
4250 private DBOSConfig config ;
4351
@@ -61,33 +69,40 @@ private void registerClassWorkflows(
6169 throw new IllegalStateException ("Cannot register workflow after DBOS is launched" );
6270 }
6371
72+ String className = implementation .getClass ().getName ();
73+ workflowRegistry .register (interfaceClass , implementation , className , instanceName );
74+
6475 Method [] methods = implementation .getClass ().getDeclaredMethods ();
6576 for (Method method : methods ) {
6677 Workflow wfAnnotation = method .getAnnotation (Workflow .class );
6778 if (wfAnnotation != null ) {
6879 method .setAccessible (true ); // In case it's not public
69- registerWorkflowMethod (wfAnnotation , implementation , instanceName , method );
80+ registerWorkflowMethod (wfAnnotation , implementation , className , instanceName , method );
7081 }
7182 }
7283 }
7384
7485 private String registerWorkflowMethod (
75- Workflow wfTag , Object target , String instanceName , Method method ) {
86+ Workflow wfTag , Object target , String className , String instanceName , Method method ) {
7687 if (dbosExecutor .get () != null ) {
7788 throw new IllegalStateException ("Cannot register workflow after DBOS is launched" );
7889 }
7990
8091 String name = wfTag .name ().isEmpty () ? method .getName () : wfTag .name ();
8192 workflowRegistry .register (
82- target .getClass ().getName (),
83- name ,
84- target ,
85- instanceName ,
86- method ,
87- wfTag .maxRecoveryAttempts ());
93+ className , name , target , instanceName , method , wfTag .maxRecoveryAttempts ());
8894 return name ;
8995 }
9096
97+ void registerLifecycleListener (DBOSLifecycleListener l ) {
98+ if (dbosExecutor .get () != null ) {
99+ throw new IllegalStateException (
100+ "Cannot register lifecycle listener after DBOS is launched" );
101+ }
102+
103+ lifecycleRegistry .add (l );
104+ }
105+
91106 void registerQueue (Queue queue ) {
92107 if (dbosExecutor .get () != null ) {
93108 throw new IllegalStateException ("Cannot build a queue after DBOS is launched" );
@@ -117,6 +132,7 @@ private void registerInternals() {
117132 void clearRegistry () {
118133 workflowRegistry .clear ();
119134 queueRegistry .clear ();
135+ lifecycleRegistry .clear ();
120136
121137 registerInternals ();
122138 }
@@ -153,7 +169,12 @@ public void launch() {
153169 var executor = new DBOSExecutor (config );
154170
155171 if (dbosExecutor .compareAndSet (null , executor )) {
156- executor .start (this , workflowRegistry .getSnapshot (), queueRegistry .getSnapshot ());
172+ executor .start (
173+ this ,
174+ new HashSet <DBOSLifecycleListener >(this .lifecycleRegistry ),
175+ workflowRegistry .getWorkflowSnapshot (),
176+ workflowRegistry .getInstanceSnapshot (),
177+ queueRegistry .getSnapshot ());
157178 }
158179 }
159180 }
@@ -211,6 +232,15 @@ public static Queue registerQueue(Queue queue) {
211232 return queue ;
212233 }
213234
235+ /**
236+ * Register a lifecycle listener that receives callbacks when DBOS is launched or shut down
237+ *
238+ * @param listener
239+ */
240+ public static void registerLifecycleListener (DBOSLifecycleListener listener ) {
241+ ensureInstance ().registerLifecycleListener (listener );
242+ }
243+
214244 /**
215245 * Reinitializes the singleton instance of DBOS with config. For use in tests that reinitialize
216246 * DBOS @DBOSConfig config dbos configuration
@@ -620,6 +650,38 @@ public static List<StepInfo> listWorkflowSteps(String workflowId) {
620650 return executor ("listWorkflowSteps" ).listWorkflowSteps (workflowId );
621651 }
622652
653+ /**
654+ * Get all workflows registered with DBOS.
655+ *
656+ * @return list of all registered workflow methods
657+ */
658+ public static Collection <RegisteredWorkflow > getRegisteredWorkflows () {
659+ return executor ("getRegisteredWorkflows" ).getWorkflows ();
660+ }
661+
662+ /**
663+ * Get all workflow classes registered with DBOS.
664+ *
665+ * @return list of all class instances containing registered workflow methods
666+ */
667+ public static Collection <RegisteredWorkflowInstance > getRegisteredWorkflowInstances () {
668+ return executor ("getRegisteredWorkflowInstances" ).getInstances ();
669+ }
670+
671+ /**
672+ * Execute a workflow based on registration and arguments. This is expected to be used by generic
673+ * callers, not app code.
674+ *
675+ * @param regWorkflow Registration of the workflow. @see getRegisteredWorkflows
676+ * @param args Workflow function arguments
677+ * @param options Execution options, such as ID, queue, and timeout/deadline
678+ * @return WorkflowHandle to the executed workflow
679+ */
680+ public static WorkflowHandle <?, ?> startWorkflow (
681+ RegisteredWorkflow regWorkflow , Object [] args , StartWorkflowOptions options ) {
682+ return executor ("executeWorkflow" ).executeWorkflow (regWorkflow , args , options , null , null );
683+ }
684+
623685 /**
624686 * Get a system database record stored by an external service A unique value is stored per
625687 * combination of service, workflowName, and key
0 commit comments