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

cancellation-system.mddocs/

0

# Cancellation System

1

2

Cancellable contexts with hierarchical cancellation propagation, listener notification, and cause tracking for managing the lifecycle of operations.

3

4

## Capabilities

5

6

### Cancellable Context Creation

7

8

Create contexts that can be independently cancelled while also cascading cancellation from their parent. Callers must ensure that cancel() or close() are called to allow garbage collection.

9

10

```java { .api }

11

/**

12

* Create a new context which is independently cancellable and cascades cancellation from its parent.

13

* @return CancellableContext that must be cancelled at some point

14

*/

15

public Context.CancellableContext withCancellation();

16

```

17

18

**Usage Example:**

19

20

```java

21

Context.CancellableContext cancellableContext = Context.current().withCancellation();

22

try {

23

cancellableContext.run(() -> {

24

Context current = Context.current();

25

while (!current.isCancelled()) {

26

// Keep working until cancelled

27

doWork();

28

}

29

});

30

} finally {

31

cancellableContext.cancel(null); // Always cancel to prevent memory leaks

32

}

33

```

34

35

### Cancellation Status Checking

36

37

Check if a context has been cancelled and retrieve the cancellation cause.

38

39

```java { .api }

40

/**

41

* Check if this context is cancelled.

42

* @return true if context is cancelled, false otherwise

43

*/

44

public boolean isCancelled();

45

46

/**

47

* Get the cause of cancellation if the context is cancelled.

48

* @return Throwable cause of cancellation, or null if not cancelled or no cause provided

49

*/

50

public Throwable cancellationCause();

51

```

52

53

**Usage Example:**

54

55

```java

56

Context.CancellableContext cancellableContext = Context.current().withCancellation();

57

58

// Check cancellation status

59

if (cancellableContext.isCancelled()) {

60

Throwable cause = cancellableContext.cancellationCause();

61

if (cause != null) {

62

System.out.println("Cancelled due to: " + cause.getMessage());

63

}

64

return; // Exit early if cancelled

65

}

66

```

67

68

### Context Cancellation

69

70

Cancel a context with an optional cause. It is safe to call cancel() multiple times - only the first call has any effect.

71

72

```java { .api }

73

public static final class CancellableContext extends Context implements Closeable {

74

/**

75

* Cancel this context and optionally provide a cause for the cancellation.

76

* @param cause Optional cause for the cancellation (can be null)

77

* @return true if this call cancelled the context, false if already cancelled

78

*/

79

public boolean cancel(Throwable cause);

80

81

/**

82

* Cleans up this object by calling cancel(null). Equivalent to cancel(null).

83

*/

84

public void close();

85

86

/**

87

* Cancel this context and detach it as the current context.

88

* @param toAttach Context to make current after detaching

89

* @param cause Optional cause for cancellation

90

*/

91

public void detachAndCancel(Context toAttach, Throwable cause);

92

}

93

```

94

95

**Usage Examples:**

96

97

```java

98

// Basic cancellation

99

Context.CancellableContext ctx = Context.current().withCancellation();

100

boolean wasCancelled = ctx.cancel(new RuntimeException("Operation timeout"));

101

102

// Using try-with-resources (automatically calls close())

103

try (Context.CancellableContext ctx = Context.current().withCancellation()) {

104

Context toRestore = ctx.attach();

105

try {

106

performOperation();

107

} finally {

108

ctx.detach(toRestore);

109

}

110

} // Automatically cancelled on close

111

112

// Cancel and detach in one operation

113

Context.CancellableContext ctx = Context.current().withCancellation();

114

Context previous = ctx.attach();

115

try {

116

performOperation();

117

} finally {

118

ctx.detachAndCancel(previous, null);

119

}

120

```

121

122

### Cancellation Listeners

123

124

Add and remove listeners that will be notified when the context becomes cancelled. Listeners are executed on the provided executor.

125

126

```java { .api }

127

/**

128

* Add a listener that will be notified when the context becomes cancelled.

129

* @param cancellationListener The listener to notify on cancellation

130

* @param executor The executor to run the listener on

131

*/

132

public void addListener(Context.CancellationListener cancellationListener, Executor executor);

133

134

/**

135

* Remove a previously added CancellationListener.

136

* @param cancellationListener The listener to remove

137

*/

138

public void removeListener(Context.CancellationListener cancellationListener);

139

140

/**

141

* A listener notified on context cancellation.

142

*/

143

public interface CancellationListener {

144

/**

145

* Notifies that a context was cancelled.

146

* @param context The newly cancelled context

147

*/

148

void cancelled(Context context);

149

}

150

```

151

152

**Usage Example:**

153

154

```java

155

Context.CancellableContext cancellableContext = Context.current().withCancellation();

156

Executor executor = Executors.newSingleThreadExecutor();

157

158

// Create a cancellation listener

159

Context.CancellationListener listener = new Context.CancellationListener() {

160

@Override

161

public void cancelled(Context context) {

162

System.out.println("Context was cancelled!");

163

Throwable cause = context.cancellationCause();

164

if (cause != null) {

165

System.out.println("Cancellation cause: " + cause.getMessage());

166

}

167

// Perform cleanup operations

168

cleanupResources();

169

}

170

};

171

172

// Add the listener

173

cancellableContext.addListener(listener, executor);

174

175

try {

176

// Perform work

177

cancellableContext.run(() -> {

178

doLongRunningWork();

179

});

180

} finally {

181

// Remove listener and cancel context

182

cancellableContext.removeListener(listener);

183

cancellableContext.cancel(null);

184

}

185

```

186

187

### Hierarchical Cancellation

188

189

Child contexts automatically inherit cancellation from their parents. When a parent context is cancelled, all descendant contexts are also cancelled.

190

191

**Usage Example:**

192

193

```java

194

// Create parent cancellable context

195

Context.CancellableContext parentContext = Context.current().withCancellation();

196

197

parentContext.run(() -> {

198

// Create child context within parent scope

199

Context.CancellableContext childContext = Context.current().withCancellation();

200

201

childContext.run(() -> {

202

// This context will be cancelled when either childContext or parentContext is cancelled

203

Context current = Context.current();

204

205

while (!current.isCancelled()) {

206

doWork();

207

}

208

209

// Check which context was cancelled

210

if (childContext.isCancelled()) {

211

System.out.println("Child context was cancelled directly");

212

} else if (parentContext.isCancelled()) {

213

System.out.println("Parent context cancellation cascaded to child");

214

}

215

});

216

217

childContext.cancel(null);

218

});

219

220

parentContext.cancel(null);

221

```

222

223

### Context Attachment for Cancellable Contexts

224

225

CancellableContext uses a surrogate for attachment to prevent external code from accessing cancellation methods.

226

227

```java { .api }

228

/**

229

* Attach this cancellable context. Uses an internal surrogate to prevent

230

* external access to cancellation methods through Context.current().

231

* @return The previously current context

232

*/

233

@Override

234

public Context attach();

235

236

/**

237

* Detach this cancellable context, restoring the previous context.

238

* @param toAttach The context returned by the corresponding attach() call

239

*/

240

@Override

241

public void detach(Context toAttach);

242

```

243

244

**Usage Example:**

245

246

```java

247

Context.CancellableContext cancellableContext = Context.current().withCancellation();

248

249

Context previous = cancellableContext.attach();

250

try {

251

// Context.current() returns a non-cancellable view

252

Context current = Context.current();

253

assert !(current instanceof Context.CancellableContext);

254

255

// But cancellation status is still accessible

256

boolean isCancelled = current.isCancelled();

257

258

} finally {

259

cancellableContext.detach(previous);

260

}

261

```