### Installation Dependencies
Source: https://github.com/gruelbox/transaction-outbox/blob/master/transactionoutbox-quarkus/README.md
Add the transactionoutbox-quarkus dependency to your project build file.
```xml
com.gruelbox
transactionoutbox-quarkus
7.0.707
```
```groovy
implementation 'com.gruelbox:transactionoutbox-quarkus:7.0.707'
```
--------------------------------
### Usage Example - Tracking scheduled tasks
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Implement the scheduled() method to track when a task is scheduled. This example records a metric and logs the event.
```java
@Override
public void scheduled(TransactionOutboxEntry entry) {
metricsService.recordScheduledTask(entry.getDescription());
logger.info("Scheduled task: {}", entry.description());
}
```
--------------------------------
### ReflectionInstantiator Implementation Example
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
An example implementation of the getInstance method using Java reflection to instantiate a class via its no-args constructor.
```java
@Override
public Object getInstance(String name) {
try {
Class> clazz = Class.forName(name);
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate " + name, e);
}
}
```
--------------------------------
### Initialize Transaction Outbox
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-outbox.md
Performs initial setup to make the TransactionOutbox instance usable. Can be called explicitly if initialization was deferred.
```java
void initialize()
```
--------------------------------
### Usage Example - Cleanup after task success
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Implement the success() method to perform cleanup actions after a task has successfully completed. This example cleans up temporary state.
```java
@Override
public void success(TransactionOutboxEntry entry) {
// Clean up temporary state created during scheduling
tempStateService.cleanup(entry.getId());
logger.debug("Task completed: {}", entry.description());
}
```
--------------------------------
### initialize
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-outbox.md
Performs initial setup, making the instance usable. Called automatically if `initializeImmediately(true)` is set (the default). Can be called explicitly if initialization was deferred.
```APIDOC
## initialize()
### Description
Performs initial setup, making the instance usable. Called automatically if `initializeImmediately(true)` is set (the default). Can be called explicitly if initialization was deferred.
### Method
(Not specified, likely a method call in a Java SDK)
### Parameters
(None specified)
### Request Example
(None specified)
### Response
#### Success Response
(No return value specified, likely void)
#### Response Example
(None specified)
### Throws
- `Exception` - Any initialization errors (e.g., database migration failures)
```
--------------------------------
### Install transaction-outbox-jooq dependency
Source: https://github.com/gruelbox/transaction-outbox/blob/master/transactionoutbox-jooq/README.md
Add the dependency to your project using Maven or Gradle.
```xml
com.gruelbox
transactionoutbox-jooq
7.0.707
```
```groovy
implementation 'com.gruelbox:transactionoutbox-jooq:7.0.707'
```
--------------------------------
### SpringInstantiator Implementation Example
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
An example implementation of the getInstance method using Spring's ApplicationContext to retrieve a bean by name.
```java
@Override
public Object getInstance(String name) {
return applicationContext.getBean(name);
}
```
--------------------------------
### Usage Example - Monitoring task failures
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Implement the failure() method to monitor task failures. This example logs the failure, checks the attempt count, and alerts if the task is approaching the maximum retry limit.
```java
@Override
public void failure(TransactionOutboxEntry entry, Throwable cause) {
logger.warn("Task failed (attempt {}): {} - {}",
entry.getAttempts() + 1,
entry.description(),
cause.getMessage());
if (entry.getAttempts() + 1 == maxAttempts - 1) {
// One more failure will block - alert now
alertService.warnTaskApproachingLimit(entry);
}
}
```
--------------------------------
### Configure explicit transaction context
Source: https://github.com/gruelbox/transaction-outbox/blob/master/transactionoutbox-jooq/README.md
Setup the outbox without thread-local synchronization by passing the DSLContext directly.
```java
// Create the DSLContext and connect the listener
var dsl = DSL.using(dataSource, SQLDialect.H2);
dsl.configuration().set(JooqTransactionManager.createListener());
// Create the outbox
var outbox = TransactionOutbox.builder()
.transactionManager(JooqTransactionManager.create(dsl))
.persistor(Persistor.forDialect(Dialect.MY_SQL_8))
.build();
```
--------------------------------
### Usage Example: Transaction Logging
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Logs the start and end of a task execution, including its duration and any errors. Useful for monitoring and debugging.
```java
@Override
public void wrapInvocation(Invocator invocator)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Invocation inv = invocator.getInvocation();
long startTime = System.currentTimeMillis();
try {
invocator.run();
long duration = System.currentTimeMillis() - startTime;
logger.info("Task executed: {} in {}ms",
inv.getMethodName(), duration);
} catch (Exception e) {
logger.error("Task failed: {} - {}",
inv.getMethodName(), e.getMessage());
throw e;
}
}
```
--------------------------------
### Configure and use TransactionOutbox
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
Demonstrates advanced configuration of the TransactionOutbox builder, including custom persistence, serialization, and event handling. Includes a usage example showing how to schedule tasks within a transaction.
```java
TransactionManager transactionManager = TransactionManager.fromDataSource(dataSource);
TransactionOutbox outbox = TransactionOutbox.builder()
// The most complex part to set up for most will be synchronizing with your existing transaction
// management. Pre-rolled implementations are available for jOOQ and Spring (see above for more information)
// and you can use those examples to synchronize with anything else by defining your own TransactionManager.
// Or, if you have no formal transaction management at the moment, why not start, using transaction-outbox's
// built-in one?
.transactionManager(transactionManager)
// Modify how requests are persisted to the database. For more complex modifications, you may wish to subclass
// DefaultPersistor, or create a completely new Persistor implementation.
.persistor(DefaultPersistor.builder()
// Selecting the right SQL dialect ensures that features such as SKIP LOCKED are used correctly.
.dialect(Dialect.POSTGRESQL_9)
// Override the table name (defaults to "TXNO_OUTBOX")
.tableName("transactionOutbox")
// Shorten the time we will wait for write locks (defaults to 2)
.writeLockTimeoutSeconds(1)
// Disable automatic creation and migration of the outbox table, forcing the application to manage
// migrations itself
.migrate(false)
// Allow the SaleType enum and Money class to be used in arguments (see example below)
.serializer(DefaultInvocationSerializer.builder()
.serializableTypes(Set.of(SaleType.class, Money.class))
.build())
.build())
// GuiceInstantiator and SpringInstantiator are great if you are using Guice or Spring DI, but what if you
// have your own service locator? Wire it in here. Fully-custom Instantiator implementations are easy to
// implement.
.instantiator(Instantiator.using(myServiceLocator::createInstance))
// Change the log level used when work cannot be submitted to a saturated queue to INFO level (the default
// is WARN, which you should probably consider a production incident). You can also change the Executor used
// for submitting work to a shared thread pool used by the rest of your application. Fully-custom Submitter
// implementations are also easy to implement, for example to cluster work.
.submitter(ExecutorSubmitter.builder()
.executor(ForkJoinPool.commonPool())
.logLevelWorkQueueSaturation(Level.INFO)
.build())
// Lower the log level when a task fails temporarily from the default WARN.
.logLevelTemporaryFailure(Level.INFO)
// 10 attempts at a task before blocking it.
.blockAfterAttempts(10)
// When calling flush(), select 0.5m records at a time.
.flushBatchSize(500_000)
// Flush once every 15 minutes only
.attemptFrequency(Duration.ofMinutes(15))
// Include Slf4j's Mapped Diagnostic Context in tasks. This means that anything in the MDC when schedule()
// is called will be recreated in the task when it runs. Very useful for tracking things like user ids and
// request ids across invocations.
.serializeMdc(true)
// Sets how long we should keep records of requests with a unique request id so duplicate requests
// can be rejected. Defaults to 7 days.
.retentionThreshold(Duration.ofDays(1))
// We can intercept and modify numerous events. The most common use is to catch blocked tasks
// and raise alerts for these to be investigated. A Slack interactive message is particularly effective here
// since it can be wired up to call unblock() automatically.
.listener(new TransactionOutboxListener() {
@Override
public void success(TransactionOutboxEntry entry) {
eventPublisher.publish(new OutboxTaskProcessedEvent(entry.getId()));
}
@Override
public void blocked(TransactionOutboxEntry entry, Throwable cause) {
eventPublisher.publish(new BlockedOutboxTaskEvent(entry.getId()));
}
@Override
public Map extractSession() {
return Map.of();
}
@Override
public void wrapInvocationAndInit(Invocator invocator) {
invocator.runUnchecked();
}
@Override
public void wrapInvocation(Invocator invocator) throws Exception {
invocator.run();
}
})
.build();
// Usage example, using the in-built transaction manager
MDC.put("SESSIONKEY", "Foo");
try {
transactionManager.inTransaction(tx -> {
writeSomeChanges(tx.connection());
outbox.schedule(getClass())
.performRemoteCall(SaleType.SALE, Money.of(10, Currency.getInstance("USD")));
});
} finally {
MDC.clear();
}
```
--------------------------------
### Production-Ready TransactionOutboxListener Implementation
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
An example of a complete listener implementation for production environments. It demonstrates how to integrate with metrics, alerting, and auditing services, and includes session extraction and invocation wrapping logic.
```java
public class ProductionListener implements TransactionOutboxListener {
private final MetricsService metrics;
private final AlertService alerts;
private final AuditService audit;
@Override
public void scheduled(TransactionOutboxEntry entry) {
metrics.incrementScheduledTasks();
}
@Override
public void success(TransactionOutboxEntry entry) {
metrics.recordTaskSuccess(entry.getDescription());
audit.logTaskCompletion(entry.getId());
}
@Override
public void failure(TransactionOutboxEntry entry, Throwable cause) {
metrics.recordTaskFailure(entry.getDescription(), entry.getAttempts());
if (entry.getAttempts() + 1 >= maxAttempts - 1) {
alerts.warn("Task approaching max attempts: " + entry.description());
}
}
@Override
public void blocked(TransactionOutboxEntry entry, Throwable cause) {
metrics.recordBlockedTask(entry.getDescription());
alerts.critical("BLOCKED: " + entry.description(), cause);
slackService.postAlert(entry, cause);
}
@Override
public Map extractSession() {
Map session = new HashMap<>();
session.put("traceId", Span.current().getSpanContext().getTraceId());
session.put("userId", getCurrentUserId());
session.put("tenantId", getCurrentTenantId());
return session;
}
@Override
public void wrapInvocationAndInit(Invocator invocator) {
Invocation inv = invocator.getInvocation();
String tenantId = inv.getSession().get("tenantId");
TenantContext.set(tenantId);
try {
invocator.runUnchecked();
} finally {
TenantContext.clear();
}
}
}
```
--------------------------------
### Usage Example: Tenant Context Restoration
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Restores tenant context before executing a task and clears it afterward. Essential for multi-tenant applications.
```java
@Override
public void wrapInvocationAndInit(Invocator invocator) {
Invocation inv = invocator.getInvocation();
String tenantId = inv.getSession().get("tenantId");
TenantContext.setCurrentTenant(tenantId);
try {
invocator.runUnchecked();
} finally {
TenantContext.clear();
}
}
```
--------------------------------
### Get Class Name for Serialization (Reflection)
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Implementation example for mapping a class to its fully-qualified name using reflection. This name is used for serialization and lookup.
```java
String getName(Class> clazz)
```
```java
@Override
public String getName(Class> clazz) {
return clazz.getName(); // e.g., "com.example.UserService"
}
```
--------------------------------
### Invocation Constructors
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Details on the different constructors available for creating Invocation objects, including parameters and usage examples.
```APIDOC
## Invocation(String className, String methodName, Class>[] parameterTypes, Object[] args)
### Description
Basic constructor without context.
### Parameters
#### Path Parameters
- **className** (String) - Required - Class name from instantiator
- **methodName** (String) - Required - Method name to invoke
- **parameterTypes** (Class>[]) - Required - Parameter types for method resolution
- **args** (Object[]) - Required - Method arguments
### Request Example
```java
Invocation inv = new Invocation(
"com.example.UserService",
"createUser",
new Class>[] { String.class, String.class },
new Object[] { "John", "john@example.com" }
);
```
## Invocation(String className, String methodName, Class>[] parameterTypes, Object[] args, Map mdc)
### Description
Legacy constructor with MDC only. Deprecated - use full constructor.
### Parameters
#### Path Parameters
- **className** (String) - Required - Class name from instantiator
- **methodName** (String) - Required - Method name to invoke
- **parameterTypes** (Class>[]) - Required - Parameter types for method resolution
- **args** (Object[]) - Required - Method arguments
- **mdc** (Map) - Required - SLF4J MDC (context map)
## Invocation(String className, String methodName, Class>[] parameterTypes, Object[] args, Map mdc, Map session)
### Description
Full constructor with both MDC and custom session state.
### Parameters
#### Path Parameters
- **className** (String) - Required - Class name from instantiator
- **methodName** (String) - Required - Method name to invoke
- **parameterTypes** (Class>[]) - Required - Parameter types for method resolution
- **args** (Object[]) - Required - Method arguments
- **mdc** (Map) - Required - SLF4J MDC, restored at execution
- **session** (Map) - Required - Custom session data from listener
### Request Example
```java
Map mdc = MDC.getCopyOfContextMap();
Map session = listener.extractSession();
Invocation inv = new Invocation(
"com.example.UserService",
"createUser",
new Class>[] { String.class },
new Object[] { "data" },
mdc,
session
);
```
```
--------------------------------
### Handle incoming remote requests with JAX-RS
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
An example endpoint to receive serialized entries and process them locally.
```java
@POST
@Path("/outbox/process")
void processOutboxEntry(String entry) {
TransactionOutboxEntry entry = somethingWhichCanSerializeTransactionOutboxEntries.deserialize(entry);
Submitter submitter = ExecutorSubmitter.builder().executor(localExecutor).logLevelWorkQueueSaturation(Level.INFO).build();
submitter.submit(entry, outbox.get()::processNow);
}
```
--------------------------------
### Usage Example - Extracting Tenant Context Session
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Implement extractSession to capture and serialize the current tenant ID if it exists in the TenantContext.
```java
@Override
public Map extractSession() {
String tenantId = TenantContext.getCurrentTenant();
if (tenantId != null) {
return Map.of("tenantId", tenantId);
}
return null;
}
```
--------------------------------
### TransactionOutbox.builder()
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-outbox.md
Creates a new builder for constructing a TransactionOutbox instance. This is the starting point for configuring and initializing the TransactionOutbox.
```APIDOC
## TransactionOutbox.builder()
### Description
Creates a new builder for constructing a `TransactionOutbox` instance.
### Method
`static TransactionOutboxBuilder builder()`
### Returns
`TransactionOutboxBuilder` instance for fluent configuration
### Usage
```java
TransactionOutbox outbox = TransactionOutbox.builder()
.transactionManager(txManager)
.persistor(Persistor.forDialect(Dialect.POSTGRESQL_9))
.build();
```
```
--------------------------------
### Handle incoming events with TransactionOutbox
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
Example of using TransactionOutbox within an SQS event handler to schedule asynchronous processing.
```java
public class FooEventHandler implements SQSEventHandler {
@Inject private TransactionOutbox outbox;
public void handle(ThingHappenedEvent event) {
outbox.schedule(FooService.class).handleEvent(event.getThingId());
}
}
```
--------------------------------
### Usage Example: Database Audit Trail
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Logs audit entries before and after task execution to track operations. Useful for security and compliance.
```java
@Override
public void wrapInvocation(Invocator invocator)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Invocation inv = invocator.getInvocation();
// Log audit entry before execution
auditService.logTaskStart(inv.getId(), inv.getClassName(), inv.getMethodName());
invocator.run();
// Log audit entry after execution
auditService.logTaskEnd(inv.getId(), "SUCCESS");
}
```
--------------------------------
### Initialize Transaction Outbox with H2 In-Memory Database
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
Use this setup when no existing transaction management or dependency injection is present. It configures an in-memory H2 database and the outbox for scheduling tasks.
```java
TransactionManager transactionManager = TransactionManager.fromConnectionDetails(
"org.h2.Driver", "jdbc:h2:mem:test;MV_STORE=TRUE", "test", "test"));
TransactionOutbox outbox = TransactionOutbox.builder()
.transactionManager(transactionManager)
.persistor(Persistor.forDialect(Dialect.H2))
.build();
transactionManager.inTransaction(tx -> {
tx.connection().createStatement().execute("INSERT INTO...");
outbox.schedule(MyClass.class).myMethod("Foo", "Bar"));
});
```
--------------------------------
### Implement a transactional sale endpoint
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
An example of a problematic implementation where a database transaction does not cover external message queue operations.
```java
@POST
@Path("/sales")
@Transactional
public SaleId createWidget(Sale sale) {
var saleId = saleRepository.save(sale);
messageQueue.postMessage(StockReductionEvent.of(sale.item(), sale.amount()));
messageQueue.postMessage(IncomeEvent.of(sale.value()));
return saleId;
}
```
--------------------------------
### Schedule a Transaction Outbox Task with Various Argument Types
Source: https://github.com/gruelbox/transaction-outbox/blob/master/transactionoutbox-jackson/README.md
Example of scheduling a task using the outbox.schedule method, demonstrating support for diverse argument types like LocalDate, String, and Integer.
```java
outbox.schedule(getClass())
.process(List.of(LocalDate.of(2000,1,1), "a", "b", 2));
```
--------------------------------
### Usage Example: OTEL Context Restoration
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Restores OpenTelemetry context (trace and span IDs) before executing a task. Useful for distributed tracing.
```java
@Override
public void wrapInvocationAndInit(Invocator invocator) {
Invocation inv = invocator.getInvocation();
Map session = inv.getSession();
if (session != null) {
String traceId = session.get("traceId");
String spanId = session.get("spanId");
// Create child span linked to parent
Span span = tracer.spanBuilder(inv.getClassName() + "." + inv.getMethodName())
.addLink(SpanContext.createFromRemoteParent(traceId, spanId, ...))
.startSpan();
try (Scope scope = span.makeCurrent()) {
invocator.runUnchecked();
} finally {
span.end();
}
} else {
invocator.runUnchecked();
}
}
```
--------------------------------
### Example Serialized JSON with Field Abbreviations
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Illustrates the compact JSON format used for serializing invocations, employing abbreviations for field names like className, methodName, parameterTypes, args, mdc, and session.
```json
{
"c": "com.example.UserService",
"m": "createUser",
"p": ["java.lang.String", "java.lang.String"],
"a": ["John", "john@example.com"],
"x": {"requestId": "req-123", "userId": "user-456"},
"s": {"tenantId": "tenant-1"}
}
```
--------------------------------
### Usage Example - Alerting on blocked tasks
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Implement the blocked method to log errors, send critical alerts, and post notifications to Slack when a task is blocked. This requires operational response.
```java
@Override
public void blocked(TransactionOutboxEntry entry, Throwable cause) {
logger.error("BLOCKED TASK - requires manual intervention: {} - {}",
entry.description(),
cause.getMessage());
// Send alert to ops team
alertService.sendCriticalAlert(new BlockedTaskAlert(
entry.getId(),
entry.description(),
cause
));
// Post to Slack with unblock button
slackService.postBlockedTaskAlert(entry, cause);
}
```
--------------------------------
### Execute Transactional Work with Return Value and Checked Exceptions
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-manager.md
Use this method to start a new transaction, execute work that may throw a checked exception and return a value. The return value is preserved, and the exception is re-thrown.
```java
T inTransactionReturnsThrows(ThrowingTransactionalSupplier work) throws E
```
```java
String result = transactionManager.inTransactionReturnsThrows(tx -> {
doSomethingThatThrows();
return "success";
});
```
--------------------------------
### Execute Transactional Work with Checked Exceptions
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-manager.md
Use this method to start a new transaction and execute work that might throw a checked exception. The exception will be re-thrown after the transaction.
```java
default void inTransactionThrows(ThrowingTransactionalWork work) throws E
```
```java
transactionManager.inTransactionThrows(tx -> {
someMethodThatThrowsCheckedException();
});
```
--------------------------------
### Get Class Name for Serialization (Spring)
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Implementation example for mapping a class to its Spring bean name. This name is used for serialization and lookup, providing an alternative to fully-qualified class names.
```java
@Override
public String getName(Class> clazz) {
String[] beanNames = applicationContext.getBeanNamesForType(clazz);
return beanNames[0]; // Use Spring bean name instead of class name
}
```
--------------------------------
### Using ReflectionInstantiator
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Demonstrates how to create an Instantiator instance that uses reflection for class instantiation.
```java
// Created by Instantiator.usingReflection()
Instantiator instantiator = Instantiator.usingReflection();
```
--------------------------------
### Configuring FunctionInstantiator
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Shows how to configure and build a FunctionInstantiator with a custom instantiation function.
```java
FunctionInstantiator instantiator = FunctionInstantiator.builder()
.fn(myCreationFunction)
.build();
```
--------------------------------
### Configuring ReflectionInstantiator
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Shows how to configure and build a ReflectionInstantiator using its builder pattern.
```java
ReflectionInstantiator instantiator = ReflectionInstantiator.builder()
.build();
```
--------------------------------
### Default wrapInvocationAndInit Method
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Provides a default implementation for wrapping invocation and initialization logic. It handles common exceptions during task execution.
```java
default void wrapInvocationAndInit(Invocator invocator) {
try {
invocator.run();
} catch (IllegalAccessException | InvocationTargetException e) {
throw new UncheckedException(e);
}
}
```
--------------------------------
### Get Method Name
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Retrieves the name of the method to be invoked.
```java
Method method = clazz.getDeclaredMethod(
invocation.getMethodName(),
invocation.getParameterTypes()
);
```
--------------------------------
### Proxying Interface as Preferred Method
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/errors.md
Demonstrates the preferred approach of using interfaces for scheduling tasks with `outbox.schedule()`, which works without the ByteBuddy dependency.
```java
// Preferred - interface
public interface IMyService { ... }
outbox.schedule(IMyService.class).doWork(); // Works without ByteBuddy
```
--------------------------------
### Configure GitHub Repository for Snapshots
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
Add the GitHub Package Repository to your build system to access continuously-delivered releases.
```xml
github-transaction-outbox
Gruelbox Github Repository
https://maven.pkg.github.com/gruelbox/transaction-outbox
```
```groovy
repositories {
maven {
name = "github-transaction-outbox"
url = uri("https://maven.pkg.github.com/gruelbox/transaction-outboxY")
credentials {
username = $githubUserName
password = $githubToken
}
}
}
```
--------------------------------
### Get Class Name
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Retrieves the class identifier used for instantiating the target object.
```java
String name = invocation.getClassName();
Object instance = instantiator.getInstance(name);
```
--------------------------------
### Configure DefaultPersistor Builder
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/persistor.md
Demonstrates how to configure the DefaultPersistor using its builder. Required options include the SQL dialect and optionally the table name, migration settings, timeouts, and serializers.
```java
DefaultPersistor.builder()
.dialect(Dialect.POSTGRESQL_9) // Required
.tableName("TXNO_OUTBOX") // Optional, defaults to TXNO_OUTBOX
.migrate(true) // Optional, defaults to true
.writeLockTimeoutSeconds(2) // Optional, defaults to 2
.serializer(invocationSerializer) // Optional, defaults to GSON
.build()
```
--------------------------------
### TransactionManager.inTransactionReturns(TransactionalSupplier supplier)
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-manager.md
Starts a new transaction and returns a value computed within it.
```APIDOC
## TransactionManager.inTransactionReturns(TransactionalSupplier supplier)
### Description
Starts a new transaction and returns a value computed within it.
### Method
T
### Parameters
#### Path Parameters
- **supplier** (TransactionalSupplier) - Required - Supplier computing a value in the transaction
### Returns
The value returned by the supplier
### Type Parameters
- **T** - The return type
### Usage
```java
User createdUser = transactionManager.inTransactionReturns(tx -> {
User user = new User("John", "john@example.com");
userDao.save(user);
return user;
});
```
```
--------------------------------
### Invocation Properties
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Details on the immutable properties of the Invocation class, including their getters and usage examples.
```APIDOC
## className
### Description
The class identifier (from `Instantiator.getName()`), not necessarily the actual class name.
### Method
```java
String getClassName()
```
### Usage
```java
String name = invocation.getClassName();
Object instance = instantiator.getInstance(name);
```
## methodName
### Description
The method name to invoke. Combined with `parameterTypes` for method resolution.
### Method
```java
String getMethodName()
```
### Usage
```java
Method method = clazz.getDeclaredMethod(
invocation.getMethodName(),
invocation.getParameterTypes()
);
```
## parameterTypes
### Description
Array of parameter types for resolving method overloads.
**Important:**
- Must match the actual parameter types exactly
- Used by reflection to find the correct method
- Empty array `{}` for no-argument methods
### Method
```java
Class>[] getParameterTypes()
```
### Usage
```java
Method method = clazz.getDeclaredMethod(
methodName,
invocation.getParameterTypes()
);
```
## args
### Description
Method arguments. Must match length and types of `parameterTypes`.
**Important:**
- Null values are preserved
- Each argument is serialized individually
- Serializable types determined by `InvocationSerializer`
### Method
```java
Object[] getArgs()
```
### Usage
```java
method.invoke(instance, invocation.getArgs());
```
## mdc
### Description
SLF4J Mapped Diagnostic Context captured at scheduling time.
**Contents (typical):**
- Request ID
- User ID
- Session ID
- Correlation ID
- Any application-specific context
**Restoration at Execution:**
```java
// During task execution
if (invocation.getMdc() != null) {
MDC.setContextMap(invocation.getMdc());
}
```
**Population (at scheduling):**
```java
// In TransactionOutboxListener
@Override
public Map extractSession() {
return MDC.getCopyOfContextMap();
}
```
### Method
```java
Map getMdc()
```
```
--------------------------------
### SpringInstantiator Usage in TransactionOutbox Builder
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Example of integrating SpringInstantiator into the TransactionOutbox builder, requiring an ApplicationContext.
```java
@Bean
public TransactionOutbox transactionOutbox(
ApplicationContext context) {
return TransactionOutbox.builder()
.instantiator(new SpringInstantiator(context))
.build();
}
```
--------------------------------
### Build TransactionOutbox Instance
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-outbox.md
Creates and initializes a TransactionOutbox instance. This is the entry point for configuring and scheduling outbox operations.
```java
abstract TransactionOutbox build()
```
--------------------------------
### Get Arguments
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Retrieves the arguments for the method call. Must match the length and types of parameterTypes.
```java
Object[] getArgs()
```
```java
method.invoke(instance, invocation.getArgs());
```
--------------------------------
### Transactional Usage Example
Source: https://github.com/gruelbox/transaction-outbox/blob/master/transactionoutbox-quarkus/README.md
Use the @Transactional annotation to manage database operations and schedule outbox events.
```java
@Transactional
public void doStuff() {
customerRepository.save(new Customer(1L, "Martin", "Carthy"));
customerRepository.save(new Customer(2L, "Dave", "Pegg"));
outbox.get().schedule(getClass()).publishCustomerCreatedEvent(1L);
outbox.get().schedule(getClass()).publishCustomerCreatedEvent(2L);
}
void publishCustomerCreatedEvent(long id) {
// Remote call here
}
```
--------------------------------
### Initialize TransactionOutbox with thread-local manager
Source: https://github.com/gruelbox/transaction-outbox/blob/master/transactionoutbox-jooq/README.md
Build the outbox instance using the JooqTransactionManager.
```java
var outbox = TransactionOutbox.builder()
.transactionManager(JooqTransactionManager.create(dsl, listener))
.persistor(Persistor.forDialect(Dialect.MY_SQL_8))
.build();
}
```
--------------------------------
### Schedule Service with Parameters
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-outbox.md
Returns a proxy of the specified class with all configured parameters applied. Method calls on this proxy are scheduled according to the outbox configuration.
```java
T schedule(Class clazz)
```
```java
outbox.with()
.uniqueRequestId("request-1")
.ordered("topic-1")
.delayForAtLeast(Duration.ofMinutes(1))
.schedule(MyService.class)
.doWork(data);
```
--------------------------------
### wrapInvocationAndInit
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Wraps the entire task execution including lock acquisition. This method is a good place to initialize session state before any database locks are acquired or important checks are performed.
```APIDOC
## wrapInvocationAndInit(Invocator invocator)
### Description
Wraps the entire task execution including lock acquisition. Good place to initialize session state.
### Parameters
#### Path Parameters
- **invocator** (Invocator) - Required - Task execution handle
### Usage Example - OTEL Context Restoration:
```java
@Override
public void wrapInvocationAndInit(Invocator invocator) {
Invocation inv = invocator.getInvocation();
Map session = inv.getSession();
if (session != null) {
String traceId = session.get("traceId");
String spanId = session.get("spanId");
// Create child span linked to parent
Span span = tracer.spanBuilder(inv.getClassName() + "." + inv.getMethodName())
.addLink(SpanContext.createFromRemoteParent(traceId, spanId, ...))
.startSpan();
try (Scope scope = span.makeCurrent()) {
invocator.runUnchecked();
} finally {
span.end();
}
} else {
invocator.runUnchecked();
}
}
```
### Usage Example - Tenant Context Restoration:
```java
@Override
public void wrapInvocationAndInit(Invocator invocator) {
Invocation inv = invocator.getInvocation();
String tenantId = inv.getSession().get("tenantId");
TenantContext.setCurrentTenant(tenantId);
try {
invocator.runUnchecked();
} finally {
TenantContext.clear();
}
}
```
```
--------------------------------
### Initialize Transaction Outbox with DataSource
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
Configure Transaction Outbox using an existing DataSource, which allows integration with connection pooling libraries like Hikari.
```java
TransactionManager transactionManager = TransactionManager.fromDataSource(dataSource);
```
--------------------------------
### Identify unsupported polymorphic collections
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
Example of a call that fails with the default serializer due to type limitations in polymorphic collections.
```java
outbox.schedule(Service.class).processList(List.of(1, "2", 3L));
```
--------------------------------
### Instantiator.using(Function, Object> fn)
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Creates an Instantiator using a custom function for instance creation. This function receives a Class object and is responsible for returning an instance of that class, often used with dependency injection frameworks.
```APIDOC
## Instantiator.using(Function, Object> fn)
### Description
Creates an instantiator using a custom function that creates instances. The function receives the class and must return an instance.
### Method
`static Instantiator using(Function, Object> fn)`
### Parameters
#### Request Body
- **fn** (Function, Object>) - Required - Function to create instances
### Returns
`Instantiator` using the provided function
### Usage Examples
```java
// Guice example
Injector injector = Guice.createInjector(...);
TransactionOutbox outbox = TransactionOutbox.builder()
.instantiator(Instantiator.using(injector::getInstance))
.build();
// Spring example
ApplicationContext context = ...;
TransactionOutbox outbox = TransactionOutbox.builder()
.instantiator(Instantiator.using(context::getBean))
.build();
// Custom Service Locator Example
Instantiator customInstantiator = Instantiator.using(clazz -> {
// Custom logic to instantiate
if (clazz == UserService.class) {
return new UserService(dependencies);
}
// Fallback
return clazz.getDeclaredConstructor().newInstance();
});
```
```
--------------------------------
### TransactionOutbox.with()
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-outbox.md
Creates a builder for scheduling requests with additional parameterization, such as unique request IDs, topics for ordered processing, and delays.
```APIDOC
## TransactionOutbox.with()
### Description
Creates a builder for scheduling requests with additional parameterization such as unique request IDs, topics for ordered processing, and delays.
### Method
`ParameterizedScheduleBuilder with()`
### Returns
`ParameterizedScheduleBuilder` for fluent parameter configuration
### Usage
```java
outbox.with()
.uniqueRequestId("request-123")
.schedule(Service.class)
.process("data");
```
```
--------------------------------
### TransactionManager.inTransaction(TransactionalWork work)
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-manager.md
Starts a new transaction and executes the transactional work, which receives a Transaction object for database access.
```APIDOC
## TransactionManager.inTransaction(TransactionalWork work)
### Description
Starts a new transaction and executes the transactional work, which receives a `Transaction` object for database access.
### Method
void
### Parameters
#### Path Parameters
- **work** (TransactionalWork) - Required - Work with access to transaction context
### Usage
```java
transactionManager.inTransaction(tx -> {
tx.connection().createStatement().execute("INSERT INTO ...");
});
```
```
--------------------------------
### TransactionManager.inTransaction(Runnable runnable)
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-manager.md
Starts a new transaction, executes the runnable within it, and commits on success or rolls back on failure.
```APIDOC
## TransactionManager.inTransaction(Runnable runnable)
### Description
Starts a new transaction, executes the runnable within it, and commits on success or rolls back on failure.
### Method
void
### Parameters
#### Path Parameters
- **runnable** (Runnable) - Required - Code to execute within the transaction
### Throws
- Any exception thrown by the runnable (wrapped if checked)
### Usage
```java
transactionManager.inTransaction(() -> {
customerDao.save(customer);
outbox.schedule(NotificationService.class).sendEmail(customer.getId());
});
```
```
--------------------------------
### Configure Transaction Outbox with Jackson for Fresh Projects
Source: https://github.com/gruelbox/transaction-outbox/blob/master/transactionoutbox-jackson/README.md
Configure the Transaction Outbox builder with JacksonInvocationSerializer for new projects. Ensure Jackson's ObjectMapper is provided.
```java
var outbox = TransactionOutbox.builder()
.persistor(DefaultPersistor.builder()
.dialect(Dialect.H2)
.serializer(JacksonInvocationSerializer.builder()
.mapper(new ObjectMapper())
.build())
.build())
```
--------------------------------
### Using FunctionInstantiator with Custom Logic
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Illustrates creating an Instantiator that uses a custom function for instantiation logic.
```java
Instantiator instantiator = Instantiator.using(clazz -> {
// Custom instantiation logic
return new CustomFactory().create(clazz);
});
```
--------------------------------
### Instantiator.usingReflection()
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Creates an Instantiator that uses Java reflection to instantiate classes via their public no-args constructor. Class names are represented by their fully-qualified names.
```APIDOC
## Instantiator.usingReflection()
### Description
Creates an instantiator that uses reflection to create instances with a no-args constructor. Class names are their fully-qualified names.
### Method
`static Instantiator usingReflection()`
### Returns
`Instantiator` using reflection-based instantiation
### Requirements
- All classes must have a public no-args constructor
- Classes must be on the application classpath at execution time
### Class Name Format
`com.example.MyService`
### Usage Example
```java
TransactionOutbox outbox = TransactionOutbox.builder()
.instantiator(Instantiator.usingReflection())
.build();
```
```
--------------------------------
### Instantiator for Multi-Version Support
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Create an Instantiator that selects the correct factory based on the service class version. This is useful when dealing with different versions of the same service.
```java
Instantiator multiVersion = Instantiator.using(clazz -> {
String versionedName = extractVersion(clazz);
switch (versionedName) {
case "com.example.UserService@v1":
return userServiceV1Factory.create();
case "com.example.UserService@v2":
return userServiceV2Factory.create();
default:
throw new IllegalArgumentException("Unknown version: " + versionedName);
}
});
```
--------------------------------
### Extract Session Data
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Example of extracting custom session data, typically from a listener, to be included in the Invocation's session map.
```java
// In TransactionOutboxListener
@Override
public Map extractSession() {
return MDC.getCopyOfContextMap();
}
```
--------------------------------
### Add Stable Dependency
Source: https://github.com/gruelbox/transaction-outbox/blob/master/README.md
Include the core library in your project build configuration.
```xml
com.gruelbox
transactionoutbox-core
7.0.707
```
```groovy
implementation 'com.gruelbox:transactionoutbox-core:7.0.707'
```
--------------------------------
### Get Parameter Types
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Retrieves the array of parameter types used for method resolution. Must match actual types exactly.
```java
Class>[] getParameterTypes()
```
```java
Method method = clazz.getDeclaredMethod(
methodName,
invocation.getParameterTypes()
);
```
--------------------------------
### GuiceInstantiator Usage with TransactionOutbox
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Demonstrates how to use GuiceInstantiator with a Guice Injector to configure TransactionOutbox.
```java
Injector injector = Guice.createInjector(...);
TransactionOutbox outbox = TransactionOutbox.builder()
.instantiator(new GuiceInstantiator(injector))
.build();
```
--------------------------------
### Manual Spring Bean Configuration
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/configuration.md
Manually configure TransactionManager, Instantiator, and TransactionOutbox beans in a Spring application. This provides explicit control over the setup.
```java
@Configuration
public class TransactionOutboxConfig {
@Bean
public TransactionManager transactionManager(
PlatformTransactionManager ptm,
DataSource dataSource) {
return new SpringTransactionManager(ptm, dataSource);
}
@Bean
public Instantiator instantiator(ApplicationContext context) {
return new SpringInstantiator(context);
}
@Bean
public TransactionOutbox transactionOutbox(
TransactionManager tm,
Instantiator inst) {
return TransactionOutbox.builder()
.transactionManager(tm)
.instantiator(inst)
.persistor(Persistor.forDialect(Dialect.POSTGRESQL_9))
.build();
}
}
```
--------------------------------
### Get Custom Session State
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Retrieves custom session state from TransactionOutboxListener.extractSession(). This state can include authentication tokens, tenant IDs, and other application-specific data.
```java
Map getSession()
```
--------------------------------
### Basic Spring Configuration for Transaction Outbox
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/spring-integration.md
Provides the necessary Spring beans for Transaction Outbox, including transaction management, instantiator, and the outbox itself with a PostgreSQL persistor and a production listener.
```java
@Configuration
public class OutboxConfig {
@Bean
public TransactionManager transactionManager(
PlatformTransactionManager platformTxManager,
DataSource dataSource) {
return new SpringTransactionManager(platformTxManager, dataSource);
}
@Bean
public Instantiator instantiator(ApplicationContext context) {
return new SpringInstantiator(context);
}
@Bean
public TransactionOutbox transactionOutbox(
TransactionManager txManager,
Instantiator instantiator) {
return TransactionOutbox.builder()
.transactionManager(txManager)
.instantiator(instantiator)
.persistor(Persistor.forDialect(Dialect.POSTGRESQL_9))
.listener(new ProductionListener())
.build();
}
}
```
--------------------------------
### Custom Instantiator for Stable Names
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
An example of a custom instantiator that uses stable names to decouple class names from refactoring, mapping simple names to stable identifiers.
```java
Instantiator stableNames = Instantiator.using(clazz -> {
String stableName = switch (clazz.getSimpleName()) {
case "UserServiceV2" -> "user-service"; // Stable name
case "EmailServiceV3" -> "email-service";
default -> clazz.getName();
};
// Look up by stable name
return serviceRegistry.get(stableName);
});
```
--------------------------------
### inTransactionThrows
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-manager.md
Starts a new transaction and executes work that may throw a checked exception. This method is suitable for operations that do not need to return a value but might encounter exceptions.
```APIDOC
## inTransactionThrows(ThrowingTransactionalWork work)
### Description
Starts a new transaction and executes work that may throw a checked exception. This method is suitable for operations that do not need to return a value but might encounter exceptions.
### Method
```java
default void inTransactionThrows(ThrowingTransactionalWork work) throws E
```
### Parameters
#### Path Parameters
* None
#### Query Parameters
* None
#### Request Body
* **work** (ThrowingTransactionalWork) - Required - Description: Work that may throw checked exceptions
### Request Example
```java
transactionManager.inTransactionThrows(tx -> {
someMethodThatThrowsCheckedException();
});
```
### Response
#### Success Response
* None (void return type)
#### Response Example
* None
```
--------------------------------
### Defer TransactionOutbox Initialization
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/configuration.md
Configure the Transaction Outbox to defer its initialization until explicitly called. This is useful for frameworks that manage their own startup sequences.
```java
// Defer initialization to structured startup
TransactionOutbox.builder()
.initializeImmediately(false)
.build();
// Later, during startup sequence
outbox.initialize();
```
--------------------------------
### Unblock with Parameter Context Manager
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/errors.md
Illustrates the correct usage of `outbox.unblock()` with a parameter context manager, requiring the explicit passing of the `transactionContext`.
```java
outbox.unblock(entryId, transactionContext); // OK
```
--------------------------------
### Schedule with Additional Parameterization
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-outbox.md
Use this to schedule requests with advanced options like unique request IDs, topics for ordered processing, or delays. This returns a builder for fluent configuration.
```java
ParameterizedScheduleBuilder with()
```
```java
outbox.with()
.uniqueRequestId("request-123")
.schedule(Service.class)
.process("data");
```
--------------------------------
### Configure DefaultInvocationSerializer with Custom Types
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/invocation.md
Configures a DefaultInvocationSerializer to include custom serializable types like enums and custom classes. This setup is used with a DefaultPersistor for database persistence.
```java
DefaultInvocationSerializer serializer = DefaultInvocationSerializer.builder()
.serializableTypes(Set.of(
MyEnumType.class,
MyCustomType.class,
MyOtherType.class
))
.build();
DefaultPersistor persistor = DefaultPersistor.builder()
.dialect(Dialect.POSTGRESQL_9)
.serializer(serializer)
.build();
```
--------------------------------
### Create Reflection Instantiator
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/instantiator.md
Creates an instantiator that uses reflection to create instances with a no-args constructor. All classes must have a public no-args constructor and be on the application classpath at execution time.
```java
static Instantiator usingReflection()
```
```java
TransactionOutbox outbox = TransactionOutbox.builder()
.instantiator(Instantiator.usingReflection())
.build();
```
--------------------------------
### Usage Example - Extracting Request Tracing Session
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/listener.md
Implement extractSession to capture and serialize OpenTelemetry trace context (traceId, spanId) and user context (userId) for request tracing.
```java
@Override
public Map extractSession() {
Map session = new HashMap<>();
// Extract OTEL trace context
String traceId = Span.current().getSpanContext().getTraceId();
String spanId = Span.current().getSpanContext().getSpanId();
session.put("traceId", traceId);
session.put("spanId", spanId);
// Extract user context
String userId = SecurityContextHolder.getContext()
.getAuthentication().getName();
session.put("userId", userId);
return session;
}
```
--------------------------------
### inTransactionReturnsThrows
Source: https://github.com/gruelbox/transaction-outbox/blob/master/_autodocs/api-reference/transaction-manager.md
Starts a new transaction, executes work that may throw a checked exception, and returns a value. This is useful for transactional operations that produce a result and can throw checked exceptions.
```APIDOC
## inTransactionReturnsThrows(ThrowingTransactionalSupplier work)
### Description
Starts a new transaction, executes work that may throw a checked exception, and returns a value. This is useful for transactional operations that produce a result and can throw checked exceptions.
### Method
```java
T inTransactionReturnsThrows(ThrowingTransactionalSupplier work) throws E
```
### Parameters
#### Path Parameters
* None
#### Query Parameters
* None
#### Request Body
* **work** (ThrowingTransactionalSupplier) - Required - Description: Work with return value and checked exceptions
### Request Example
```java
String result = transactionManager.inTransactionReturnsThrows(tx -> {
doSomethingThatThrows();
return "success";
});
```
### Response
#### Success Response
* **T** (Type T) - Description: The value returned by the work
#### Response Example
```json
{
"example": "success"
}
```
```