Skip to main content
Timeouts ensure that tasks and workflows don’t run indefinitely. Infinitic provides flexible timeout configuration with grace periods for cleanup.

The @Timeout Annotation

Use the @Timeout annotation to define timeout behavior for tasks and workflows:
import io.infinitic.annotations.Timeout

@Timeout(with = CustomTimeout::class)
class MyService : MyServiceInterface {
    override fun process(data: String): Result {
        // Task implementation
    }
}

Method-Level Timeout

Apply timeouts to individual methods:
class MyService : MyServiceInterface {
    
    @Timeout(with = ShortTimeout::class)
    override fun quickOperation(): Result {
        // This method has a 10-second timeout
    }
    
    @Timeout(with = LongTimeout::class)
    override fun slowOperation(): Result {
        // This method has a 5-minute timeout
    }
}

Implementing WithTimeout

Create custom timeout policies by implementing the WithTimeout interface:
import io.infinitic.tasks.WithTimeout

class CustomTimeout : WithTimeout {
    override fun getTimeoutSeconds(): Double? {
        return 30.0 // 30-second timeout
    }
    
    override fun getGracePeriodAfterTimeoutSeconds(): Double {
        return 5.0 // 5-second grace period for cleanup
    }
}

WithTimeout Interface

The WithTimeout interface defines two methods:
fun interface WithTimeout {
    /**
     * Returns the timeout duration in seconds.
     * Null means no timeout is set.
     */
    fun getTimeoutSeconds(): Double?
    
    /**
     * Returns the grace period after the timeout in seconds.
     * Default is 0 (no grace period).
     */
    fun getGracePeriodAfterTimeoutSeconds(): Double = 0.0
}
getTimeoutSeconds():
  • Returns the timeout duration in seconds
  • Return null for no timeout
getGracePeriodAfterTimeoutSeconds():
  • Returns the grace period after timeout in seconds
  • Default is 0.0 (no grace period)
  • Allows time for cleanup operations

Timeout Patterns

Simple Timeout

class TenSecondTimeout : WithTimeout {
    override fun getTimeoutSeconds(): Double = 10.0
}

Timeout with Grace Period

class TimeoutWithGrace : WithTimeout {
    override fun getTimeoutSeconds(): Double = 60.0
    
    override fun getGracePeriodAfterTimeoutSeconds(): Double = 10.0
}
The grace period allows your task to:
  • Close database connections
  • Release resources
  • Save partial state
  • Send cleanup messages

No Timeout

class NoTimeout : WithTimeout {
    override fun getTimeoutSeconds(): Double? = null
}

Environment-Based Timeout

class ConfigurableTimeout : WithTimeout {
    override fun getTimeoutSeconds(): Double? {
        return System.getenv("TASK_TIMEOUT")?.toDoubleOrNull() ?: 30.0
    }
}

Workflow Method Timeouts

Set timeouts for workflow methods when dispatching them:
val workflow = client.newWorkflow(MyWorkflow::class.java)
val deferred = workflow.processAsync(data)

// The workflow method inherits timeout from @Timeout annotation

Handling Timeout Events

When a timeout occurs, Infinitic emits timeout events:
  • taskTimedOut - Task exceeded its timeout
  • methodTimedOut - Workflow method exceeded its timeout
  • remoteMethodTimedOut - Child workflow method timed out

Catching Timeouts in Workflows

try {
    val result = task.longRunningOperation()
} catch (e: TaskTimedOutException) {
    logger.warn("Task timed out, using fallback")
    return fallbackValue
}

Timer Completion

You can manually complete timers in workflows:
// Complete all timers in a workflow
client.completeTimersAsync(workflowStub)

// Complete specific timer by method ID
client.completeTimersAsync(workflowStub, methodId)

Timeout Configuration

Class-Level Configuration

@Timeout(with = DefaultTimeout::class)
class MyService {
    // All methods inherit this timeout
    fun operation1() { }
    fun operation2() { }
}

Method Override

@Timeout(with = DefaultTimeout::class)
class MyService {
    
    // Uses class-level timeout
    fun normalOperation() { }
    
    // Overrides with method-level timeout
    @Timeout(with = LongTimeout::class)
    fun specialOperation() { }
}

Best Practices

Base timeouts on actual task duration plus a buffer for variability and system load.
Always provide a grace period for tasks that need to clean up resources or save state.
Quick operations should have short timeouts, while batch processing might need longer ones.
High timeout rates indicate operations are consistently taking longer than expected.
Always handle timeout exceptions gracefully with appropriate fallback logic.
Test that your tasks properly handle timeouts and grace periods.

Timeout vs Retry

Timeouts and retries work together:
  1. Task starts executing
  2. Timeout is reached
  3. Grace period allows cleanup
  4. Task fails with timeout error
  5. Retry policy determines if retry should occur
@Timeout(with = ThirtySecondTimeout::class)
@Retry(with = ExponentialBackoff::class)
class ResilientService {
    // Will timeout after 30 seconds
    // Then retry with exponential backoff
}

Build docs developers (and LLMs) love