or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cancellation-system.mdcontext-management.mddeadline-management.mdexecution-utilities.mdindex.md

execution-utilities.mddocs/

0

# Execution Utilities

1

2

Utilities for wrapping Runnables, Callables, and Executors to automatically propagate context across thread boundaries and asynchronous operations.

3

4

## Capabilities

5

6

### Direct Execution

7

8

Execute code immediately within a specific context scope. These methods handle attach/detach automatically.

9

10

```java { .api }

11

/**

12

* Immediately run a Runnable with this context as the current context.

13

* @param r Runnable to run

14

*/

15

public void run(Runnable r);

16

17

/**

18

* Immediately call a Callable with this context as the current context.

19

* @param c Callable to call

20

* @return Result of the callable

21

* @throws Exception If the callable throws an exception

22

*/

23

public <V> V call(Callable<V> c) throws Exception;

24

```

25

26

**Usage Examples:**

27

28

```java

29

Context.Key<String> USER_KEY = Context.key("user");

30

Context withUser = Context.current().withValue(USER_KEY, "alice");

31

32

// Run a task with the context

33

withUser.run(() -> {

34

String user = USER_KEY.get(); // "alice"

35

processUserRequest(user);

36

});

37

38

// Call a task that returns a value

39

String result = withUser.call(() -> {

40

String user = USER_KEY.get(); // "alice"

41

return fetchUserData(user);

42

});

43

44

// Exception handling with call()

45

try {

46

Integer count = withUser.call(() -> {

47

return performCalculation();

48

});

49

} catch (Exception e) {

50

System.out.println("Calculation failed: " + e.getMessage());

51

}

52

```

53

54

### Runnable and Callable Wrapping

55

56

Wrap Runnables and Callables so they execute with a specific context, useful for passing tasks to other threads or executors.

57

58

```java { .api }

59

/**

60

* Wrap a Runnable so that it executes with this context as the current context.

61

* @param r Runnable to wrap

62

* @return Wrapped Runnable that propagates this context

63

*/

64

public Runnable wrap(Runnable r);

65

66

/**

67

* Wrap a Callable so that it executes with this context as the current context.

68

* @param c Callable to wrap

69

* @return Wrapped Callable that propagates this context

70

*/

71

public <C> Callable<C> wrap(Callable<C> c);

72

```

73

74

**Usage Examples:**

75

76

```java

77

Context.Key<String> REQUEST_ID_KEY = Context.key("requestId");

78

Context withRequestId = Context.current().withValue(REQUEST_ID_KEY, "req-123");

79

80

ExecutorService executor = Executors.newFixedThreadPool(4);

81

82

// Wrap a Runnable for execution in another thread

83

Runnable task = withRequestId.wrap(() -> {

84

String requestId = REQUEST_ID_KEY.get(); // "req-123"

85

processRequest(requestId);

86

});

87

88

// Submit to executor - context will be propagated

89

executor.submit(task);

90

91

// Wrap a Callable for execution in another thread

92

Callable<String> computation = withRequestId.wrap(() -> {

93

String requestId = REQUEST_ID_KEY.get(); // "req-123"

94

return performComputation(requestId);

95

});

96

97

// Submit and get result - context was propagated

98

Future<String> result = executor.submit(computation);

99

String computationResult = result.get();

100

```

101

102

### Fixed Context Executor

103

104

Wrap an Executor so that all tasks submitted to it execute with a specific context. The context is fixed at creation time.

105

106

```java { .api }

107

/**

108

* Wrap an Executor so that it always executes with this context as the current context.

109

* @param e Executor to wrap

110

* @return Wrapped Executor that propagates this context for all tasks

111

*/

112

public Executor fixedContextExecutor(Executor e);

113

```

114

115

**Usage Example:**

116

117

```java

118

Context.Key<String> TENANT_KEY = Context.key("tenant");

119

Context withTenant = Context.current().withValue(TENANT_KEY, "tenant-abc");

120

121

ExecutorService baseExecutor = Executors.newFixedThreadPool(4);

122

123

// Create executor that always uses the tenant context

124

Executor tenantExecutor = withTenant.fixedContextExecutor(baseExecutor);

125

126

// All tasks submitted to this executor will have the tenant context

127

tenantExecutor.execute(() -> {

128

String tenant = TENANT_KEY.get(); // "tenant-abc"

129

processTenantRequest(tenant);

130

});

131

132

tenantExecutor.execute(() -> {

133

String tenant = TENANT_KEY.get(); // "tenant-abc"

134

performTenantMaintenance(tenant);

135

});

136

137

// Even if current context changes, the executor still uses the fixed context

138

Context.current().withValue(TENANT_KEY, "different-tenant").run(() -> {

139

tenantExecutor.execute(() -> {

140

String tenant = TENANT_KEY.get(); // Still "tenant-abc"!

141

handleTenantData(tenant);

142

});

143

});

144

```

145

146

### Current Context Executor

147

148

Create an Executor that propagates whatever the current context is at the time each task is submitted. This is a static method that captures context dynamically.

149

150

```java { .api }

151

/**

152

* Create an executor that propagates the current context when execute() is called.

153

* The context is captured at submission time, not creation time.

154

* @param e Base executor to wrap

155

* @return Wrapped Executor that propagates the current context for each task

156

*/

157

public static Executor currentContextExecutor(Executor e);

158

```

159

160

**Usage Example:**

161

162

```java

163

Context.Key<String> USER_KEY = Context.key("user");

164

ExecutorService baseExecutor = Executors.newFixedThreadPool(4);

165

166

// Create executor that captures current context for each task

167

Executor contextExecutor = Context.currentContextExecutor(baseExecutor);

168

169

// Task submitted with user "alice" context

170

Context.current().withValue(USER_KEY, "alice").run(() -> {

171

contextExecutor.execute(() -> {

172

String user = USER_KEY.get(); // "alice"

173

processUserTask(user);

174

});

175

});

176

177

// Different task submitted with user "bob" context

178

Context.current().withValue(USER_KEY, "bob").run(() -> {

179

contextExecutor.execute(() -> {

180

String user = USER_KEY.get(); // "bob"

181

processUserTask(user);

182

});

183

});

184

185

// Tasks submitted without user context

186

contextExecutor.execute(() -> {

187

String user = USER_KEY.get(); // null (no user in context)

188

processGuestTask();

189

});

190

```

191

192

### Context Propagation Patterns

193

194

Common patterns for propagating context across asynchronous operations.

195

196

**CompletableFuture with Context:**

197

198

```java

199

Context.Key<String> TRACE_ID_KEY = Context.key("traceId");

200

Context withTrace = Context.current().withValue(TRACE_ID_KEY, "trace-456");

201

202

ExecutorService executor = Executors.newFixedThreadPool(4);

203

Executor contextExecutor = Context.currentContextExecutor(executor);

204

205

CompletableFuture<String> future = withTrace.call(() -> {

206

return CompletableFuture

207

.supplyAsync(() -> {

208

String traceId = TRACE_ID_KEY.get(); // "trace-456"

209

return fetchData(traceId);

210

}, contextExecutor)

211

.thenApplyAsync(data -> {

212

String traceId = TRACE_ID_KEY.get(); // "trace-456"

213

return processData(data, traceId);

214

}, contextExecutor);

215

});

216

```

217

218

**Thread Pool with Shared Context:**

219

220

```java

221

Context.Key<String> SERVICE_KEY = Context.key("service");

222

Context serviceContext = Context.current().withValue(SERVICE_KEY, "payment-service");

223

224

ExecutorService pool = Executors.newFixedThreadPool(10);

225

Executor serviceExecutor = serviceContext.fixedContextExecutor(pool);

226

227

// All tasks in this pool will have service context

228

for (int i = 0; i < 100; i++) {

229

final int taskId = i;

230

serviceExecutor.execute(() -> {

231

String service = SERVICE_KEY.get(); // "payment-service"

232

processPaymentTask(taskId, service);

233

});

234

}

235

```

236

237

**Mixed Context Propagation:**

238

239

```java

240

Context.Key<String> REQUEST_KEY = Context.key("request");

241

Context.Key<String> SESSION_KEY = Context.key("session");

242

243

ExecutorService executor = Executors.newFixedThreadPool(4);

244

Executor currentContextExecutor = Context.currentContextExecutor(executor);

245

246

// Base context with session

247

Context sessionContext = Context.current().withValue(SESSION_KEY, "session-789");

248

249

sessionContext.run(() -> {

250

// Each request gets its own context but inherits session

251

for (int i = 0; i < 5; i++) {

252

final String requestId = "req-" + i;

253

254

Context.current().withValue(REQUEST_KEY, requestId).run(() -> {

255

// This task will have both session and request context

256

currentContextExecutor.execute(() -> {

257

String session = SESSION_KEY.get(); // "session-789"

258

String request = REQUEST_KEY.get(); // "req-0", "req-1", etc.

259

handleRequest(request, session);

260

});

261

});

262

}

263

});

264

```