or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

account-settings.mdalias-version-management.mdclient-management.mdconcurrency-performance.mdevent-source-mapping.mdfunction-invocation.mdfunction-management.mdfunction-url-management.mdhigh-level-invocation.mdindex.mdlayer-management.mdpermissions-policies.mdruntime-management.mdsecurity-code-signing.mdtagging.mdwaiters-polling.md

high-level-invocation.mddocs/

0

# High-Level Invocation Utilities

1

2

Type-safe, annotation-driven Lambda function invocation through proxy interfaces that eliminate boilerplate code and provide compile-time safety for remote function calls.

3

4

## Capabilities

5

6

### LambdaInvokerFactory

7

8

Central factory class for creating type-safe proxy interfaces that enable seamless Lambda function invocation with automatic serialization and error handling.

9

10

#### Factory Creation and Configuration

11

12

```java { .api }

13

/**

14

* Factory for creating type-safe Lambda function invocation proxies

15

* Enables annotation-driven function calls with automatic serialization

16

* @see LambdaInvokerFactory.Builder for configuration options

17

*/

18

public class LambdaInvokerFactory {

19

20

/**

21

* Creates builder instance for configuring Lambda invoker factory

22

* @return LambdaInvokerFactoryConfig.Builder for fluent configuration

23

*/

24

public static LambdaInvokerFactoryConfig.Builder builder();

25

26

/**

27

* Creates type-safe proxy for Lambda function invocation interface

28

* @param interfaceClass Interface class annotated with @LambdaFunction methods

29

* @return Proxy implementation that handles Lambda invocation transparently

30

* @throws LambdaSerializationException if interface cannot be proxied

31

*/

32

public <T> T build(Class<T> interfaceClass);

33

}

34

35

/**

36

* Configuration builder for Lambda invoker factory

37

* Provides fluent API for setting up invocation behavior and serialization

38

*/

39

public static class LambdaInvokerFactoryConfig.Builder {

40

41

/**

42

* Sets Lambda client for function invocation

43

* @param lambdaClient AWSLambda client instance (required)

44

* @return Builder instance for method chaining

45

*/

46

public Builder lambdaClient(AWSLambda lambdaClient);

47

48

/**

49

* Sets function name resolver for dynamic function name resolution

50

* @param functionNameResolver Custom resolver implementation

51

* @return Builder instance for method chaining

52

*/

53

public Builder functionNameResolver(LambdaFunctionNameResolver functionNameResolver);

54

55

/**

56

* Sets object mapper for JSON serialization/deserialization

57

* @param objectMapper Jackson ObjectMapper instance

58

* @return Builder instance for method chaining

59

*/

60

public Builder objectMapper(ObjectMapper objectMapper);

61

62

/**

63

* Sets log type for function invocation

64

* @param logType LogType.None or LogType.Tail

65

* @return Builder instance for method chaining

66

*/

67

public Builder logType(LogType logType);

68

69

/**

70

* Builds configured Lambda invoker factory

71

* @return Configured LambdaInvokerFactory instance

72

* @throws IllegalArgumentException if required configuration is missing

73

*/

74

public LambdaInvokerFactory build();

75

}

76

```

77

78

### Function Name Resolution

79

80

Interface and implementations for resolving Lambda function names from interface methods.

81

82

#### LambdaFunctionNameResolver Interface

83

84

```java { .api }

85

/**

86

* Interface for resolving Lambda function names from method metadata

87

* Enables custom function name resolution strategies beyond annotations

88

*/

89

public interface LambdaFunctionNameResolver {

90

91

/**

92

* Resolves Lambda function name for method invocation

93

* @param method Method being invoked with potential @LambdaFunction annotation

94

* @param lambdaFunction Annotation instance if present, null otherwise

95

* @return Function name to invoke (name, ARN, or partial ARN)

96

* @throws IllegalArgumentException if function name cannot be resolved

97

*/

98

String getFunctionName(Method method, LambdaFunction lambdaFunction);

99

}

100

```

101

102

#### Default Function Name Resolver

103

104

```java { .api }

105

/**

106

* Default implementation of function name resolution

107

* Uses @LambdaFunction annotation value or method name as fallback

108

*/

109

public class DefaultLambdaFunctionNameResolver implements LambdaFunctionNameResolver {

110

111

/**

112

* Resolves function name using annotation value or method name

113

* @param method Method being invoked

114

* @param lambdaFunction Annotation instance if present

115

* @return Resolved function name

116

*/

117

@Override

118

public String getFunctionName(Method method, LambdaFunction lambdaFunction);

119

}

120

```

121

122

### Annotations and Configuration

123

124

Annotation-based configuration for mapping interface methods to Lambda functions.

125

126

#### LambdaFunction Annotation

127

128

```java { .api }

129

/**

130

* Annotation for mapping interface methods to Lambda functions

131

* Provides metadata for function invocation and behavior customization

132

*/

133

@Target(ElementType.METHOD)

134

@Retention(RetentionPolicy.RUNTIME)

135

public @interface LambdaFunction {

136

137

/**

138

* Lambda function name, ARN, or partial ARN

139

* If empty, uses method name or function name resolver

140

* @return Function identifier for invocation

141

*/

142

String functionName() default "";

143

144

/**

145

* Function invocation type

146

* @return InvocationType.RequestResponse (synchronous) or InvocationType.Event (asynchronous)

147

*/

148

InvocationType invocationType() default InvocationType.RequestResponse;

149

150

/**

151

* Log type for invocation response

152

* @return LogType.None or LogType.Tail to include logs

153

*/

154

LogType logType() default LogType.None;

155

156

/**

157

* Function version or alias qualifier

158

* @return Version number, alias name, or empty for $LATEST

159

*/

160

String qualifier() default "";

161

}

162

```

163

164

### Exception Handling

165

166

Specialized exceptions for high-level invocation error scenarios.

167

168

#### LambdaFunctionException

169

170

```java { .api }

171

/**

172

* Wrapper exception for Lambda function execution errors

173

* Provides access to function error details and metadata

174

*/

175

public class LambdaFunctionException extends Exception {

176

177

/**

178

* Creates exception with function error details

179

* @param message Error message from function execution

180

* @param handled Whether error was handled by function

181

* @param type Error type classification

182

*/

183

public LambdaFunctionException(String message, boolean handled, String type);

184

185

/**

186

* Creates exception with cause chain

187

* @param message Error message

188

* @param cause Underlying cause exception

189

*/

190

public LambdaFunctionException(String message, Throwable cause);

191

192

/**

193

* Indicates if error was handled by function code

194

* @return true if function caught and handled error, false for unhandled exceptions

195

*/

196

public boolean isHandled();

197

198

/**

199

* Gets error type classification

200

* @return Error type string (e.g., "User", "System")

201

*/

202

public String getType();

203

}

204

```

205

206

#### LambdaSerializationException

207

208

```java { .api }

209

/**

210

* Exception for JSON serialization/deserialization errors

211

* Thrown when request/response objects cannot be converted to/from JSON

212

*/

213

public class LambdaSerializationException extends RuntimeException {

214

215

/**

216

* Creates serialization exception with message and cause

217

* @param message Descriptive error message

218

* @param cause Underlying serialization error

219

*/

220

public LambdaSerializationException(String message, Throwable cause);

221

}

222

```

223

224

## Usage Examples

225

226

### Basic Function Interface

227

228

```java

229

// Define interface with Lambda function methods

230

public interface UserService {

231

232

@LambdaFunction(functionName = "user-authentication")

233

UserAuthResult authenticateUser(AuthRequest request) throws LambdaFunctionException;

234

235

@LambdaFunction(functionName = "user-profile-service")

236

UserProfile getUserProfile(String userId) throws LambdaFunctionException;

237

238

@LambdaFunction(functionName = "user-preferences",

239

invocationType = InvocationType.Event)

240

void updatePreferencesAsync(String userId, Map<String, Object> preferences);

241

}

242

243

// Request/Response classes

244

public class AuthRequest {

245

private String username;

246

private String password;

247

// getters and setters

248

}

249

250

public class UserAuthResult {

251

private boolean authenticated;

252

private String token;

253

private long expiresAt;

254

// getters and setters

255

}

256

257

public class UserProfile {

258

private String userId;

259

private String email;

260

private String displayName;

261

// getters and setters

262

}

263

```

264

265

### Creating and Using Function Proxies

266

267

```java

268

AWSLambda lambdaClient = AWSLambdaClientBuilder.defaultClient();

269

270

// Create factory with configuration

271

LambdaInvokerFactory invokerFactory = LambdaInvokerFactory.builder()

272

.lambdaClient(lambdaClient)

273

.logType(LogType.Tail)

274

.build();

275

276

// Create type-safe proxy

277

UserService userService = invokerFactory.build(UserService.class);

278

279

// Use proxy like local interface

280

try {

281

AuthRequest authRequest = new AuthRequest();

282

authRequest.setUsername("john.doe");

283

authRequest.setPassword("secret123");

284

285

UserAuthResult result = userService.authenticateUser(authRequest);

286

if (result.isAuthenticated()) {

287

System.out.println("Authentication successful. Token: " + result.getToken());

288

289

// Get user profile

290

UserProfile profile = userService.getUserProfile("john.doe");

291

System.out.println("Welcome, " + profile.getDisplayName());

292

293

// Update preferences asynchronously

294

Map<String, Object> preferences = new HashMap<>();

295

preferences.put("theme", "dark");

296

preferences.put("notifications", true);

297

userService.updatePreferencesAsync("john.doe", preferences);

298

299

} else {

300

System.out.println("Authentication failed");

301

}

302

303

} catch (LambdaFunctionException e) {

304

System.err.println("Function error: " + e.getMessage());

305

System.err.println("Error type: " + e.getType());

306

System.err.println("Handled: " + e.isHandled());

307

}

308

```

309

310

### Advanced Configuration with Custom Resolver

311

312

```java

313

// Custom function name resolver for environment-based routing

314

public class EnvironmentFunctionNameResolver implements LambdaFunctionNameResolver {

315

private final String environment;

316

317

public EnvironmentFunctionNameResolver(String environment) {

318

this.environment = environment;

319

}

320

321

@Override

322

public String getFunctionName(Method method, LambdaFunction lambdaFunction) {

323

String baseName = (lambdaFunction != null && !lambdaFunction.functionName().isEmpty())

324

? lambdaFunction.functionName()

325

: method.getName();

326

327

return baseName + "-" + environment;

328

}

329

}

330

331

// Configure factory with custom resolver

332

LambdaInvokerFactory factory = LambdaInvokerFactory.builder()

333

.lambdaClient(lambdaClient)

334

.functionNameResolver(new EnvironmentFunctionNameResolver("prod"))

335

.objectMapper(createCustomObjectMapper())

336

.logType(LogType.Tail)

337

.build();

338

339

private ObjectMapper createCustomObjectMapper() {

340

ObjectMapper mapper = new ObjectMapper();

341

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

342

mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

343

return mapper;

344

}

345

```

346

347

### Complex Service Interface

348

349

```java

350

public interface OrderProcessingService {

351

352

@LambdaFunction(functionName = "order-validation")

353

ValidationResult validateOrder(Order order) throws LambdaFunctionException;

354

355

@LambdaFunction(functionName = "payment-processing",

356

qualifier = "PROD")

357

PaymentResult processPayment(PaymentRequest payment) throws LambdaFunctionException;

358

359

@LambdaFunction(functionName = "inventory-check")

360

InventoryStatus checkInventory(List<String> productIds) throws LambdaFunctionException;

361

362

@LambdaFunction(functionName = "order-fulfillment",

363

invocationType = InvocationType.Event)

364

void initiateFullfillment(String orderId, Address shippingAddress);

365

366

@LambdaFunction(functionName = "notification-service",

367

invocationType = InvocationType.Event,

368

logType = LogType.Tail)

369

void sendOrderConfirmation(String orderId, String customerEmail);

370

}

371

372

// Usage in order processing workflow

373

public class OrderProcessor {

374

private final OrderProcessingService service;

375

376

public OrderProcessor(LambdaInvokerFactory factory) {

377

this.service = factory.build(OrderProcessingService.class);

378

}

379

380

public void processOrder(Order order) {

381

try {

382

// Validate order synchronously

383

ValidationResult validation = service.validateOrder(order);

384

if (!validation.isValid()) {

385

throw new OrderProcessingException("Order validation failed: " +

386

validation.getErrors());

387

}

388

389

// Check inventory synchronously

390

List<String> productIds = order.getItems().stream()

391

.map(OrderItem::getProductId)

392

.collect(Collectors.toList());

393

394

InventoryStatus inventory = service.checkInventory(productIds);

395

if (!inventory.isAvailable()) {

396

throw new OrderProcessingException("Insufficient inventory");

397

}

398

399

// Process payment synchronously

400

PaymentRequest paymentRequest = createPaymentRequest(order);

401

PaymentResult payment = service.processPayment(paymentRequest);

402

if (!payment.isSuccessful()) {

403

throw new OrderProcessingException("Payment failed: " +

404

payment.getErrorMessage());

405

}

406

407

// Initiate fulfillment asynchronously

408

service.initiateFullfillment(order.getId(), order.getShippingAddress());

409

410

// Send confirmation asynchronously

411

service.sendOrderConfirmation(order.getId(), order.getCustomerEmail());

412

413

} catch (LambdaFunctionException e) {

414

handleFunctionError(e);

415

throw new OrderProcessingException("Lambda function error", e);

416

}

417

}

418

419

private void handleFunctionError(LambdaFunctionException e) {

420

// Log error details

421

System.err.println("Lambda function error: " + e.getMessage());

422

System.err.println("Error type: " + e.getType());

423

System.err.println("Was handled: " + e.isHandled());

424

425

// Handle specific error types

426

if ("User".equals(e.getType()) && e.isHandled()) {

427

// Business logic error - safe to retry or handle gracefully

428

} else {

429

// System error - may need different handling

430

}

431

}

432

}

433

```

434

435

### Error Handling and Retry Logic

436

437

```java

438

public class ResilientLambdaService {

439

private final OrderProcessingService service;

440

private final int maxRetries = 3;

441

442

public ResilientLambdaService(LambdaInvokerFactory factory) {

443

this.service = factory.build(OrderProcessingService.class);

444

}

445

446

public ValidationResult validateOrderWithRetry(Order order) {

447

int attempt = 0;

448

while (attempt < maxRetries) {

449

try {

450

return service.validateOrder(order);

451

} catch (LambdaFunctionException e) {

452

attempt++;

453

454

if (shouldRetry(e) && attempt < maxRetries) {

455

System.out.println("Retrying validation, attempt " + (attempt + 1));

456

try {

457

Thread.sleep(1000 * attempt); // Exponential backoff

458

} catch (InterruptedException ie) {

459

Thread.currentThread().interrupt();

460

throw new RuntimeException("Interrupted during retry", ie);

461

}

462

} else {

463

throw new RuntimeException("Validation failed after " + attempt + " attempts", e);

464

}

465

}

466

}

467

throw new RuntimeException("Max retries exceeded");

468

}

469

470

private boolean shouldRetry(LambdaFunctionException e) {

471

// Retry on system errors but not on business logic errors

472

return !e.isHandled() || !"User".equals(e.getType());

473

}

474

}

475

```

476

477

### Testing Lambda Interfaces

478

479

```java

480

// Mock implementation for testing

481

public class MockOrderProcessingService implements OrderProcessingService {

482

483

@Override

484

public ValidationResult validateOrder(Order order) {

485

// Mock validation logic

486

return new ValidationResult(true, Collections.emptyList());

487

}

488

489

@Override

490

public PaymentResult processPayment(PaymentRequest payment) {

491

// Mock payment processing

492

return new PaymentResult(true, "txn_12345", null);

493

}

494

495

@Override

496

public InventoryStatus checkInventory(List<String> productIds) {

497

// Mock inventory check

498

return new InventoryStatus(true, Collections.emptyMap());

499

}

500

501

@Override

502

public void initiateFullfillment(String orderId, Address shippingAddress) {

503

// Mock fulfillment - no-op for async methods

504

}

505

506

@Override

507

public void sendOrderConfirmation(String orderId, String customerEmail) {

508

// Mock notification - no-op for async methods

509

}

510

}

511

512

// Unit test

513

@Test

514

public void testOrderProcessing() {

515

OrderProcessor processor = new OrderProcessor(

516

// Use mock factory that returns mock implementation

517

createMockFactory()

518

);

519

520

Order testOrder = createTestOrder();

521

processor.processOrder(testOrder);

522

523

// Verify expected behavior

524

// ...

525

}

526

```

527

528

## Exception Handling

529

530

Common exceptions when using high-level invocation:

531

532

- **LambdaFunctionException**: Function execution errors with details about error type and handling

533

- **LambdaSerializationException**: JSON serialization/deserialization failures

534

- **IllegalArgumentException**: Invalid interface class or missing required configuration

535

- **RuntimeException**: Proxy creation failures or invocation errors

536

537

## Best Practices

538

539

### Interface Design

540

- Keep interfaces focused and cohesive around related functionality

541

- Use descriptive method names that clearly indicate the Lambda function purpose

542

- Define clear input/output data models with proper validation

543

- Separate synchronous and asynchronous operations logically

544

545

### Configuration Management

546

- Use environment-specific function name resolvers for deployment flexibility

547

- Configure appropriate timeout values for synchronous invocations

548

- Set up proper error handling and retry mechanisms

549

- Use custom object mappers for specific serialization requirements

550

551

### Error Handling

552

- Distinguish between business logic errors and system errors

553

- Implement appropriate retry strategies based on error types

554

- Log sufficient error details for debugging and monitoring

555

- Use circuit breaker patterns for resilient service communication

556

557

### Performance Optimization

558

- Use asynchronous invocations for non-blocking operations

559

- Pool Lambda invoker factory instances to avoid repeated initialization

560

- Monitor invocation performance and optimize function implementations

561

- Consider batching for high-volume operations where appropriate