-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CORE-20867 Implement retry topic to handle persistent transient RPC C…
…lient errors (#6385) The current mediator messaging pattern in Corda can encounter an retry loop when transient errors are received from other Corda workers. This retry loop blocks flow topic partitions from progressing and it has been observed that the corda cluster affected can become permanently unstable due to the effects of consumer lag. This pattern is used by the flow worker to perform synchronous HTTP calls to various workers, including verification, token, crypto, uniqueness, and persistence workers. To address this issue, a separate Kafka topic is dedicated to handling retries. This will allow the primary ingestion topics to continue processing unaffected flows, while introducing finite retry logic for flows impacted by transient errors. Additionally AVRO version is bumped to fix a vulnerability
- Loading branch information
Showing
17 changed files
with
489 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
...c/main/kotlin/net/corda/flow/pipeline/handlers/events/ExternalEventRetryRequestHandler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package net.corda.flow.pipeline.handlers.events | ||
|
||
import net.corda.data.flow.event.external.ExternalEventResponse | ||
import net.corda.data.flow.event.external.ExternalEventRetryRequest | ||
import net.corda.flow.pipeline.events.FlowEventContext | ||
import net.corda.flow.pipeline.exceptions.FlowEventException | ||
import net.corda.utilities.debug | ||
import org.osgi.service.component.annotations.Component | ||
import org.slf4j.Logger | ||
import org.slf4j.LoggerFactory | ||
|
||
/** | ||
* Handles pre-processing of events that are intended to trigger a resend of an external event. | ||
* This can be triggered by the mediator in the event of transient errors. | ||
*/ | ||
@Component(service = [FlowEventHandler::class]) | ||
class ExternalEventRetryRequestHandler : FlowEventHandler<ExternalEventRetryRequest> { | ||
|
||
private companion object { | ||
val log: Logger = LoggerFactory.getLogger(this::class.java.enclosingClass) | ||
private const val TOKEN_RETRY = "TokenRetry" | ||
} | ||
|
||
override val type = ExternalEventRetryRequest::class.java | ||
|
||
override fun preProcess(context: FlowEventContext<ExternalEventRetryRequest>): FlowEventContext<ExternalEventRetryRequest> { | ||
val checkpoint = context.checkpoint | ||
val externalEventRetryRequest = context.inputEventPayload | ||
|
||
if (!checkpoint.doesExist) { | ||
log.debug { | ||
"Received a ${ExternalEventRetryRequest::class.simpleName} for flow [${context.inputEvent.flowId}] that " + | ||
"does not exist. The event will be discarded. ${ExternalEventRetryRequest::class.simpleName}: " + | ||
externalEventRetryRequest | ||
} | ||
throw FlowEventException( | ||
"ExternalEventRetryRequestHandler received a ${ExternalEventRetryRequest::class.simpleName} for flow" + | ||
" [${context.inputEvent.flowId}] that does not exist" | ||
) | ||
} | ||
|
||
val externalEventState = checkpoint.externalEventState | ||
val retryRequestId: String = externalEventRetryRequest.requestId | ||
val externalEventStateRequestId = externalEventState?.requestId | ||
if (externalEventState == null) { | ||
log.debug { | ||
"Received an ${ExternalEventRetryRequest::class.simpleName} with request id: " + | ||
"$retryRequestId while flow [${context.inputEvent.flowId} is not waiting " + | ||
"for an ${ExternalEventResponse::class.simpleName}. " + | ||
"${ExternalEventRetryRequest::class.simpleName}: $externalEventRetryRequest" | ||
} | ||
throw FlowEventException( | ||
"ExternalEventRetryRequestHandler received an ${ExternalEventRetryRequest::class.simpleName} with request id: " + | ||
"$retryRequestId while flow [${context.inputEvent.flowId} is not waiting " + | ||
"for an ${ExternalEventResponse::class.simpleName}" | ||
) | ||
} | ||
//Discard events not related. Some token requests do not contain the external event id so this validation will allow all token | ||
// requests to be resent. e.g TokenForceClaimRelease | ||
else if (externalEventStateRequestId != retryRequestId && retryRequestId != TOKEN_RETRY) { | ||
throw FlowEventException( | ||
"Discarding retry request received with requestId $retryRequestId. This is likely a stale record polled. Checkpoint " + | ||
"is currently waiting to receive a response for requestId $externalEventStateRequestId" | ||
) | ||
} | ||
|
||
return context | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.