Strategy C: Deferred Execution (Async)
SummaryDeferred execution via Kafka enhances scalability and responsiveness.
Deferred execution via Kafka enhances scalability and responsiveness.
Deferred execution via Kafka enhances scalability and responsiveness.
Strategy C: Deferred Execution (Async)
Introduction
Deferred execution, as embodied by Strategy C, represents a paradigm shift in how systems approach the processing of client requests. By decoupling the initial response from the actual task completion, this strategy enables systems to return a response before the task is fully executed, thereby enhancing responsiveness and scalability. This section delves into the intricacies of deferred execution, exploring its underlying principles, architectural implications, and the role of technologies like Kafka in facilitating eventual consistency.
Principles of Deferred Execution
At its core, deferred execution is about managing the client’s expectations while ensuring that the system can handle requests without compromising performance. The HTTP 202 (Accepted) status code plays a pivotal role in this context, signaling to the client that the request has been accepted for processing but not yet completed. This distinction is crucial, as it allows the system to acknowledge the request immediately while deferring the actual processing until later.
Architectural Considerations
The implementation of deferred execution necessitates a careful examination of the system’s architecture. Key considerations include the selection of an appropriate message broker, such as Kafka, to handle the asynchronous processing of requests. Kafka’s ability to provide durable delivery guarantees, coupled with its support for log compaction, makes it an attractive choice for systems requiring eventual consistency.
Role of Kafka
Kafka serves as the backbone of the deferred execution strategy, providing a fault-tolerant and scalable messaging system. By utilizing Kafka as an immutable intent-log, the system can ensure that all requests are processed in a sequential manner, thereby preventing inconsistencies. Furthermore, Kafka’s consumer lag metric offers valuable insights into the system’s health, enabling the dynamic adjustment of execution strategies in response to changing conditions.
Implementation Details
The actual implementation of deferred execution involves several critical components, including the controller-level logic for determining the execution strategy, the Kafka producer settings for ensuring durable delivery, and the consumer logic for processing intents. The following Java code snippet illustrates the controller-level decoupling implementation:
@PostMapping("/intents")
public ResponseEntity<Void> processIntent(@RequestBody IntentRequest intent) {
Strategy strategy = evaluator.determineStrategy(intent.getCriticality());
if (strategy == Strategy.ASYNC) {
kafkaTemplate.send("intent-topic", intent.getEntityId(), intent);
return ResponseEntity.accepted()
.header("X-Execution-Strategy", "ASYNC")
.build(); // Returns 202
}
// Fallback or SYNC logic
service.processSync(intent);
return ResponseEntity.status(HttpStatus.CREATED).build(); // Returns 201
}
Similarly, the Kafka consumer implementation for the ‘eventually consistent’ path is as follows:
@KafkaListener(topics = "intent-topic", groupId = "execution-group")
public void consumeIntent(IntentRequest intent, @Header("kafka_receivedMessageKey") String key) {
log.info("Executing deferred intent for entity: {}", key);
try {
repository.applyIntentPayload(intent);
metrics.markSuccess(intent.getType());
} catch (Exception e) {
deadLetterQueue.send(intent);
}
}
Comparison of Execution Strategies
The choice of execution strategy has significant implications for the system’s performance, scalability, and consistency. The following table summarizes the key differences between immediate (SYNC), deferred (ASYNC), and optimistic execution strategies:
| Request Type | Consistency Priority | Response Code | Durability Guarantee |
|---|---|---|---|
| Immediate (SYNC) | Strong / Linearizable | 201 Created | Disk + Quorum |
| Deferred (ASYNC) | Eventual | 202 Accepted | Kafka ISR (acks=all) |
| Optimistic | Low Latency | 201 Created | Local + Background Sync |
Conclusion
In conclusion, the deferred execution strategy, as facilitated by Kafka, offers a powerful approach to achieving eventual consistency in distributed systems. By carefully considering the architectural implications and implementation details, developers can create scalable and responsive systems that meet the demands of modern applications. As the system’s requirements evolve, the ability to dynamically adjust execution strategies in response to changing conditions will become increasingly important.
Sources
[1] https://www.linkedin.com/pulse/design-patterns-command-pattern-explained-c-examples-ruhul-amin-7gv3c [2] https://www.geeksforgeeks.org/system-design/eventual-consistency-in-distributive-systems-learn-system-design/ [3] https://stackoverflow.com/questions/65217718/best-practice-to-make-client-handle-eventual-consistency-of-microservices