How to Configure Execution Timoutouts for Extensions Using firstExtension() in cp-ddd-framework

To configure execution timeouts for extensions in the cp-ddd-framework, invoke the three-argument firstExtension(Class<Ext>, IIdentity, int) overload with a positive millisecond value, which propagates the timeout to ExtensionInvocationHandler and enforces limits via Future.get() with ExtTimeoutException on breach.

The cp-ddd-framework provides a robust extension-point mechanism for domain-driven design applications, allowing developers to configure execution timeouts for extensions to prevent long-running operations from blocking critical business flows. The firstExtension() method in io.github.dddplus.runtime.DDD provides overloads that control timeout behavior through the underlying proxy invocation handler.

Understanding the firstExtension() Timeout API

The DDD class exposes multiple pathways for retrieving extension instances. The commonly used two-argument overload automatically disables timeout protection by passing a zero value:

public static <Ext extends IDomainExtension> Ext firstExtension(@NonNull Class<Ext> extClazz,
                                                              @NonNull IIdentity identity) {
    return firstExtension(extClazz, identity, 0);
}

As implemented in dddplus-runtime/src/main/java/io/github/dddplus/runtime/DDD.java (lines 67-71), this method delegates to the three-argument variant while passing 0 milliseconds, meaning no timeout enforcement occurs.

To configure execution timeouts for extensions, call the overload that accepts a timeoutInMs parameter:

ExtensionInvocationHandler<Ext, R> proxy =
        new ExtensionInvocationHandler<>(extClazz, identity, null, null,
                                        InternalIndexer.registeredInterceptor(),
                                        timeoutInMs);
return proxy.createProxy();

This construction appears at lines 89-91 in DDD.java, where the timeoutInMs value propagates directly into the ExtensionInvocationHandler constructor.

How Timeout Enforcement Works

The ExtensionInvocationHandler class located at dddplus-runtime/src/main/java/io/github/dddplus/runtime/ExtensionInvocationHandler.java manages timeout logic during method invocation through the following execution path:

  • Validation (lines 38-40): The handler checks if timeoutInMs > 0 to determine whether timeout protection is active.
  • Delegation (lines 48-50): When enabled, the invocation routes to invokeExtensionMethodWithTimeout().
  • Execution (lines 65-70): The framework executes the extension method within a Future and calls Future.get(timeout, TimeUnit.MILLISECONDS).
  • Exception Translation: When the timeout expires, the handler catches TimeoutException and wraps it as ExtTimeoutException (defined in dddplus-runtime/src/main/java/io/github/dddplus/runtime/ExtTimeoutException.java, lines 11-14).

Practical Implementation Examples

When you configure execution timeouts for extensions in production environments, always specify the timeout explicitly to prevent indefinite blocking:

import io.github.dddplus.runtime.DDD;
import io.github.dddplus.ext.IDomainExtension;
import io.github.dddplus.ext.IIdentity;

public class OrderIdentity implements IIdentity {
    private final String orderNo;
    
    public OrderIdentity(String orderNo) { 
        this.orderNo = orderNo; 
    }
    
    public String getOrderNo() { return orderNo; }
}

public class ExtensionClient {
    public void processWithTimeout() {
        IIdentity identity = new OrderIdentity("ORD12345");
        
        // Configure 3000ms timeout for this extension execution
        MyExtension ext = DDD.firstExtension(MyExtension.class, identity, 3000);
        
        try {
            ext.process();
        } catch (ExtTimeoutException e) {
            // Handle timeout - extension exceeded 3 seconds
            logger.error("Extension execution timed out", e);
        }
    }
}

For extension points requiring consistent timeout policies across your application, create a utility wrapper that encapsulates the timeout value:

public class ExtensionHelper {
    private static final int DEFAULT_TIMEOUT_MS = 5000;
    
    public static <T extends IDomainExtension> T getExtensionWithTimeout(
            Class<T> clazz, IIdentity identity) {
        return DDD.firstExtension(clazz, identity, DEFAULT_TIMEOUT_MS);
    }
}

Summary

  • The two-argument firstExtension(Class, IIdentity) overload disables timeouts by passing 0 milliseconds to the handler.
  • To configure execution timeouts for extensions, use the three-argument overload with a positive millisecond value.
  • The ExtensionInvocationHandler enforces timeouts using Future.get() and converts TimeoutException to ExtTimeoutException.
  • Key source files: DDD.java (lines 67-71, 89-91), ExtensionInvocationHandler.java (lines 38-50, 65-70), and ExtTimeoutException.java (lines 11-14).

Frequently Asked Questions

What happens when I pass 0 as the timeout value to firstExtension()?

Passing 0 milliseconds disables timeout protection entirely, allowing the extension to run indefinitely until completion or failure. The ExtensionInvocationHandler bypasses the Future.get(timeout, TimeUnit.MILLISECONDS) call and executes the extension method directly without time constraints, as implemented in the validation logic at lines 38-40 of ExtensionInvocationHandler.java.

How does cp-ddd-framework handle timeout exceptions?

When an extension exceeds the specified timeout duration, the framework throws ExtTimeoutException (defined in ExtTimeoutException.java, lines 11-14). This exception wraps the underlying java.util.concurrent.TimeoutException and provides context about which extension point and identity triggered the timeout, enabling precise error handling in your domain logic at the call site.

Can I set a global default timeout for all extension calls?

The framework does not provide a global configuration property for extension timeouts. You must explicitly pass the timeout value in each firstExtension() call or create a wrapper utility class that encapsulates your standard timeout values, ensuring consistent protection across your application without modifying the core framework classes in dddplus-runtime.

Is the timeout enforced per-method call or per-extension instance?

The timeout is enforced per-method invocation. Each time you call a method on the proxy returned by firstExtension(), the ExtensionInvocationHandler creates a new execution context with the configured timeout. This means different method calls on the same extension instance can have different effective timeouts if you obtain new proxy instances with different timeout configurations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →