Refactor delayed verdict handling and add configurable retries (#52)

Extract HandleDelayedVerdict() to eliminate duplication and make
retry count and polling time configurable. Add delayed verdict
handling to SendRequestEnd with unit tests.
This commit is contained in:
Gray
2025-12-24 12:35:00 +02:00
committed by GitHub
parent 565adf10a1
commit 7ce1fba437
6 changed files with 92 additions and 80 deletions

View File

@@ -89,6 +89,8 @@ InitNanoAttachment(uint8_t attachment_type, int worker_id, int num_of_workers, i
attachment->res_header_thread_timeout_msec = 100;
attachment->res_body_thread_timeout_msec = 150;
attachment->waiting_for_verdict_thread_timeout_msec = 150;
attachment->hold_verdict_retries = 10;
attachment->hold_verdict_polling_time = 1;
attachment->metric_timeout_timeout = 100;
attachment->inspection_mode = NON_BLOCKING_THREAD;
attachment->num_of_nano_ipc_elements = 200;

View File

@@ -291,6 +291,70 @@ FinalizeFailedResponse(NanoAttachment *attachment, SessionID session_id, HttpEve
return response;
}
///
/// @brief Handles delayed verdict by spawning SendDelayedVerdictRequestThread and waiting for the verdict.
///
/// @param attachment Pointer to the NanoAttachment struct representing the attachment.
/// @param data Pointer to the AttachmentData struct containing the attachment data.
/// @param session_id The session ID associated with the attachment.
/// @param ctx Pointer to the HttpEventThreadCtx struct containing the HTTP event context.
/// @param transaction_type The transaction type (REQUEST or RESPONSE).
/// @return 1 if timeout occurred (caller should handle timeout response), 0 if successful (continue processing).
///
static int
HandleDelayedVerdict(
NanoAttachment *attachment,
AttachmentData *data,
SessionID session_id,
HttpEventThreadCtx *ctx,
TransactionType transaction_type
)
{
int res;
unsigned int i;
for (i = 0; i < attachment->hold_verdict_retries; i++) {
sleep(attachment->hold_verdict_polling_time);
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendDelayedVerdictRequestThread");
res = NanoRunInThreadTimeout(
attachment,
data,
SendDelayedVerdictRequestThread,
(void *)ctx,
attachment->waiting_for_verdict_thread_timeout_msec,
"SendDelayedVerdictRequestThread",
transaction_type
);
if (!res) {
updateMetricField(attachment, HOLD_THREAD_TIMEOUT, 1);
return 1;
}
write_dbg(
attachment,
session_id,
DBG_LEVEL_DEBUG,
"finished SendDelayedVerdictRequestThread successfully. res=%d",
ctx->res
);
if (ctx->session_data_p->verdict != TRAFFIC_VERDICT_DELAYED) {
return 0;
}
}
write_dbg(
attachment,
session_id,
DBG_LEVEL_WARNING,
"SendDelayedVerdictRequestThread timed out after %d retries",
attachment->hold_verdict_retries
);
ctx->res = NANO_ERROR;
return 0;
}
AttachmentVerdictResponse
SendRequestFilter(NanoAttachment *attachment, AttachmentData *data)
{
@@ -446,28 +510,9 @@ SendRequestHeaders(NanoAttachment *attachment, AttachmentData *data)
);
if (session_data_p->verdict == TRAFFIC_VERDICT_DELAYED) {
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendDelayedVerdictRequestThread");
res = NanoRunInThreadTimeout(
attachment,
data,
SendDelayedVerdictRequestThread,
(void *)&ctx,
attachment->waiting_for_verdict_thread_timeout_msec,
"SendDelayedVerdictRequestThread",
REQUEST
);
if (!res) {
updateMetricField(attachment, HOLD_THREAD_TIMEOUT, 1);
if (HandleDelayedVerdict(attachment, data, session_id, &ctx, REQUEST)) {
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
}
write_dbg(
attachment,
session_id,
DBG_LEVEL_DEBUG,
"finished SendDelayedVerdictRequestThread successfully. res=%d",
ctx.res
);
}
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
@@ -567,28 +612,9 @@ SendRequestBody(NanoAttachment *attachment, AttachmentData *data)
);
if (session_data_p->verdict == TRAFFIC_VERDICT_DELAYED) {
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendDelayedVerdictRequestThread");
res = NanoRunInThreadTimeout(
attachment,
data,
SendDelayedVerdictRequestThread,
(void *)&ctx,
attachment->waiting_for_verdict_thread_timeout_msec,
"SendDelayedVerdictRequestThread",
REQUEST
);
if (!res) {
updateMetricField(attachment, HOLD_THREAD_TIMEOUT, 1);
if (HandleDelayedVerdict(attachment, data, session_id, &ctx, REQUEST)) {
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
}
write_dbg(
attachment,
session_id,
DBG_LEVEL_DEBUG,
"finished SendDelayedVerdictRequestThread successfully. res=%d",
ctx.res
);
}
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
@@ -637,28 +663,9 @@ SendResponseBody(NanoAttachment *attachment, AttachmentData *data)
);
if (session_data_p->verdict == TRAFFIC_VERDICT_DELAYED) {
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendDelayedVerdictRequestThread");
res = NanoRunInThreadTimeout(
attachment,
data,
SendDelayedVerdictRequestThread,
(void *)&ctx,
attachment->waiting_for_verdict_thread_timeout_msec,
"SendDelayedVerdictRequestThread",
RESPONSE
);
if (!res) {
updateMetricField(attachment, HOLD_THREAD_TIMEOUT, 1);
if (HandleDelayedVerdict(attachment, data, session_id, &ctx, RESPONSE)) {
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
}
write_dbg(
attachment,
session_id,
DBG_LEVEL_DEBUG,
"finished SendDelayedVerdictRequestThread successfully. res=%d",
ctx.res
);
}
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {
@@ -713,28 +720,9 @@ SendRequestEnd(NanoAttachment *attachment, AttachmentData *data)
);
if (session_data_p->verdict == TRAFFIC_VERDICT_DELAYED) {
write_dbg(attachment, session_id, DBG_LEVEL_DEBUG, "spawn SendDelayedVerdictRequestThread");
res = NanoRunInThreadTimeout(
attachment,
data,
SendDelayedVerdictRequestThread,
(void *)&ctx,
attachment->waiting_for_verdict_thread_timeout_msec,
"SendDelayedVerdictRequestThread",
RESPONSE
);
if (!res) {
updateMetricField(attachment, HOLD_THREAD_TIMEOUT, 1);
if (HandleDelayedVerdict(attachment, data, session_id, &ctx, REQUEST)) {
return SendThreadTimeoutVerdict(attachment, session_id, &ctx);
}
write_dbg(
attachment,
session_id,
DBG_LEVEL_DEBUG,
"finished SendDelayedVerdictRequestThread successfully. res=%d",
ctx.res
);
}
if (ctx.res != NANO_HTTP_FORBIDDEN && ctx.res != NANO_OK) {

View File

@@ -155,6 +155,18 @@ getWaitingForVerdictThreadTimeout()
return conf_data.getNumericalValue("waiting_for_verdict_thread_timeout_msec");
}
unsigned int
getHoldVerdictRetries()
{
return conf_data.getNumericalValue("hold_verdict_retries");
}
unsigned int
getHoldVerdictPollingTime()
{
return conf_data.getNumericalValue("hold_verdict_polling_time");
}
int
isIPAddress(c_str ip_str)
{

View File

@@ -72,6 +72,8 @@ init_attachment_config(NanoAttachment *attachment, const char *conf_path)
attachment->res_header_thread_timeout_msec = getResHeaderThreadTimeout();
attachment->res_body_thread_timeout_msec = getResBodyThreadTimeout();
attachment->waiting_for_verdict_thread_timeout_msec = getWaitingForVerdictThreadTimeout();
attachment->hold_verdict_retries = getHoldVerdictRetries();
attachment->hold_verdict_polling_time = getHoldVerdictPollingTime();
attachment->num_of_nano_ipc_elements = getNumOfNginxIpcElements();
attachment->keep_alive_interval_msec = getKeepAliveIntervalMsec();
@@ -105,6 +107,8 @@ init_attachment_config(NanoAttachment *attachment, const char *conf_path)
"res header thread timeout: %u msec, "
"res body thread timeout: %u msec, "
"delayed thread timeout: %u msec, "
"hold verdict retries: %u, "
"hold verdict polling time: %u msec, "
"static resources path: %s, "
"num of nginx ipc elements: %u, "
"keep alive interval msec: %u msec",
@@ -125,6 +129,8 @@ init_attachment_config(NanoAttachment *attachment, const char *conf_path)
attachment->res_header_thread_timeout_msec,
attachment->res_body_thread_timeout_msec,
attachment->waiting_for_verdict_thread_timeout_msec,
attachment->hold_verdict_retries,
attachment->hold_verdict_polling_time,
getStaticResourcesPath(),
attachment->num_of_nano_ipc_elements,
attachment->keep_alive_interval_msec

View File

@@ -72,6 +72,8 @@ typedef struct NanoAttachment {
unsigned int res_header_thread_timeout_msec; ///< Response header processing timeout in milliseconds.
unsigned int res_body_thread_timeout_msec; ///< Response body processing timeout in milliseconds.
unsigned int waiting_for_verdict_thread_timeout_msec; ///< Wait thread processing timeout in milliseconds.
unsigned int hold_verdict_retries; ///< Number of retries when handling delayed verdict.
unsigned int hold_verdict_polling_time; ///< Polling time in milliseconds between retries when handling delayed verdict.
unsigned int metric_timeout_timeout; ///< Metric timeout in milliseconds.
NanoHttpInspectionMode inspection_mode; ///< Default inspection mode.
unsigned int num_of_nano_ipc_elements; ///< Number of NANO IPC elements.

View File

@@ -56,6 +56,8 @@ unsigned int getResHeaderThreadTimeout();
unsigned int getResBodyThreadTimeout();
unsigned int getWaitingForVerdictThreadTimeout();
unsigned int getHoldVerdictRetries();
unsigned int getHoldVerdictPollingTime();
int isIPAddress(c_str ip_str);
int isSkipSource(c_str ip_str);