@@ -189,10 +189,38 @@ export interface WriteStreamOptions {
189189 serializationType ?: WorkflowSerializationFormat ;
190190}
191191
192+ /**
193+ * Options for DBOS operations that poll the system database while waiting.
194+ */
195+ export interface PollingOptions {
196+ /**
197+ * Milliseconds to wait between system database polls. Must be positive and finite.
198+ *
199+ * This affects DB-backed polling waits. Live in-process workflow handles that await
200+ * an already-running promise do not poll.
201+ */
202+ pollingIntervalMs ?: number ;
203+ }
204+
205+ /**
206+ * Options for `DBOS.getResult` and workflow handle `getResult`.
207+ */
208+ export interface GetResultOptions extends PollingOptions {
209+ /** Timeout in seconds; if the workflow does not complete before the timeout, `null` will be returned */
210+ timeoutSeconds ?: number ;
211+ /** Absolute deadline as a UNIX epoch timestamp in milliseconds; if the workflow does not complete before this time, `null` will be returned */
212+ deadlineEpochMS ?: number ;
213+ }
214+
215+ /**
216+ * Options for `DBOS.waitFirst`.
217+ */
218+ export type WaitFirstOptions = PollingOptions ;
219+
192220/**
193221 * Options for `DBOS.recv`
194222 */
195- export interface RecvOptions {
223+ export interface RecvOptions extends PollingOptions {
196224 /** Timeout in seconds; if no message is received before the timeout (default 60 seconds), `null` will be returned */
197225 timeoutSeconds ?: number ;
198226 /** Absolute deadline as a UNIX epoch timestamp in milliseconds; if no message is received before this time, `null` will be returned */
@@ -202,7 +230,7 @@ export interface RecvOptions {
202230/**
203231 * Options for `DBOS.getEvent`
204232 */
205- export interface GetEventOptions {
233+ export interface GetEventOptions extends PollingOptions {
206234 /** Timeout in seconds; if no event is received before the timeout (default 60 seconds), `null` will be returned */
207235 timeoutSeconds ?: number ;
208236 /** Absolute deadline as a UNIX epoch timestamp in milliseconds; if no event is received before this time, `null` will be returned */
@@ -238,7 +266,9 @@ export interface SetEventOptions {
238266 serializationType ?: WorkflowSerializationFormat ;
239267}
240268
241- export function resolveTimeoutSeconds ( options ?: number | RecvOptions | GetEventOptions ) : number | undefined {
269+ export function resolveTimeoutSeconds (
270+ options ?: number | RecvOptions | GetEventOptions | GetResultOptions ,
271+ ) : number | undefined {
242272 if ( options === undefined ) return undefined ;
243273 if ( typeof options === 'number' ) return options ;
244274 if ( options . deadlineEpochMS !== undefined ) {
@@ -247,6 +277,16 @@ export function resolveTimeoutSeconds(options?: number | RecvOptions | GetEventO
247277 return options . timeoutSeconds ;
248278}
249279
280+ export function resolvePollingIntervalMs ( options ?: number | PollingOptions ) : number | undefined {
281+ if ( options === undefined || typeof options === 'number' ) return undefined ;
282+ const interval = options . pollingIntervalMs ;
283+ if ( interval === undefined ) return undefined ;
284+ if ( ! Number . isFinite ( interval ) || interval <= 0 ) {
285+ throw new DBOSError ( 'pollingIntervalMs must be a positive finite number' ) ;
286+ }
287+ return interval ;
288+ }
289+
250290export function resolveDelayEpochMS ( options : number | SetWorkflowDelayOptions ) : number {
251291 if ( typeof options === 'number' ) {
252292 if ( options <= 0 ) throw new DBOSError ( 'delaySeconds must be greater than 0' ) ;
@@ -774,21 +814,24 @@ export class DBOS {
774814 * @param timeoutSeconds - Maximum time to wait for result; if not provided, the operation does not time out
775815 * @returns The return value of the workflow, or throws the exception thrown by the workflow, or `null` if times out
776816 */
777- static async getResult < T > ( workflowID : string , timeoutSeconds ?: number ) : Promise < T | null > {
817+ static async getResult < T > ( workflowID : string , options ?: number | GetResultOptions ) : Promise < T | null > {
778818 ensureDBOSIsLaunched ( 'getResult' ) ;
819+ const timeoutSeconds = resolveTimeoutSeconds ( options ) ;
820+ const pollingIntervalMs = resolvePollingIntervalMs ( options ) ;
779821 let timerFuncID : number | undefined = undefined ;
780822 if ( DBOS . isWithinWorkflow ( ) && timeoutSeconds !== undefined ) {
781823 // Reserve the function ID synchronously, before any await.
782824 timerFuncID = functionIDGetIncrement ( ) ;
783825 }
784- return await DBOS . getResultInternal ( workflowID , timeoutSeconds , timerFuncID , undefined ) ;
826+ return await DBOS . getResultInternal ( workflowID , timeoutSeconds , timerFuncID , undefined , pollingIntervalMs ) ;
785827 }
786828
787829 static async getResultInternal < T > (
788830 workflowID : string ,
789831 timeoutSeconds ?: number ,
790832 timerFuncID ?: number ,
791833 assignedFuncID ?: number ,
834+ pollingIntervalMs ?: number ,
792835 ) : Promise < T | null > {
793836 return await runInternalStep (
794837 async ( ) => {
@@ -797,6 +840,7 @@ export class DBOS {
797840 timeoutSeconds ,
798841 DBOS . workflowID ,
799842 timerFuncID ,
843+ pollingIntervalMs ,
800844 ) ;
801845 if ( ! rres ) return null ;
802846 if ( rres ?. cancelled ) {
@@ -820,8 +864,12 @@ export class DBOS {
820864 * @param handles - Non-empty array of workflow handles to wait on
821865 * @returns The first handle whose workflow has completed
822866 */
823- static async waitFirst ( handles : WorkflowHandle < unknown > [ ] ) : Promise < WorkflowHandle < unknown > > {
867+ static async waitFirst (
868+ handles : WorkflowHandle < unknown > [ ] ,
869+ options ?: WaitFirstOptions ,
870+ ) : Promise < WorkflowHandle < unknown > > {
824871 ensureDBOSIsLaunched ( 'waitFirst' ) ;
872+ const pollingIntervalMs = resolvePollingIntervalMs ( options ) ;
825873 if ( handles . length === 0 ) {
826874 throw new Error ( 'handles must not be empty' ) ;
827875 }
@@ -836,7 +884,11 @@ export class DBOS {
836884 const workflowIds = [ ...handleMap . keys ( ) ] ;
837885
838886 const completedId = await runInternalStep ( async ( ) => {
839- return await DBOSExecutor . globalInstance ! . systemDatabase . awaitFirstWorkflowId ( workflowIds , DBOS . workflowID ) ;
887+ return await DBOSExecutor . globalInstance ! . systemDatabase . awaitFirstWorkflowId (
888+ workflowIds ,
889+ DBOS . workflowID ,
890+ pollingIntervalMs ,
891+ ) ;
840892 } , 'DBOS.waitFirst' ) ;
841893
842894 return handleMap . get ( completedId ) ! ;
@@ -1362,12 +1414,14 @@ export class DBOS {
13621414 const functionID : number = functionIDGetIncrement ( ) ;
13631415 const timeoutFunctionID : number = functionIDGetIncrement ( ) ;
13641416 const timeoutSeconds = resolveTimeoutSeconds ( options ) ;
1417+ const pollingIntervalMs = resolvePollingIntervalMs ( options ) ;
13651418 const msg = await DBOSExecutor . globalInstance ! . systemDatabase . recv (
13661419 DBOS . workflowID ! ,
13671420 functionID ,
13681421 timeoutFunctionID ,
13691422 topic ,
13701423 timeoutSeconds ,
1424+ pollingIntervalMs ,
13711425 ) ;
13721426
13731427 return ( await deserializeValue ( msg . serializedValue , msg . serialization , DBOS . #executor. serializer ) ) as T ;
@@ -1426,6 +1480,7 @@ export class DBOS {
14261480 static async getEvent < T > ( workflowID : string , key : string , options ?: number | GetEventOptions ) : Promise < T | null > {
14271481 ensureDBOSIsLaunched ( 'getEvent' ) ;
14281482 const timeoutSeconds = resolveTimeoutSeconds ( options ) ;
1483+ const pollingIntervalMs = resolvePollingIntervalMs ( options ) ;
14291484 if ( DBOS . isWithinWorkflow ( ) ) {
14301485 if ( ! DBOS . isInWorkflow ( ) ) {
14311486 throw new DBOSInvalidWorkflowTransitionError (
@@ -1445,10 +1500,11 @@ export class DBOS {
14451500 key ,
14461501 timeoutSeconds ?? DBOSExecutor . defaultNotificationTimeoutSec ,
14471502 params ,
1503+ pollingIntervalMs ,
14481504 ) ;
14491505 return ( await deserializeValue ( evt . serializedValue , evt . serialization , DBOS . #executor. serializer ) ) as T ;
14501506 }
1451- return DBOS . #executor. getEvent ( workflowID , key , timeoutSeconds ) ;
1507+ return DBOS . #executor. getEvent ( workflowID , key , timeoutSeconds , pollingIntervalMs ) ;
14521508 }
14531509
14541510 /**
0 commit comments