static void DefaultIoTHubSendReportedStateCompletedCallback()

in src/utils/d2c_messaging/src/d2c_messaging.c [203:327]


static void DefaultIoTHubSendReportedStateCompletedCallback(int http_status_code, void* context)
{
    Log_Debug("context:0x%x", context);
    ADUC_D2C_Message_Processing_Context* message_processing_context = (ADUC_D2C_Message_Processing_Context*)context;
    int computed = false;

    if (message_processing_context == NULL)
    {
        Log_Error("context is NULL");
        return;
    }

    if (!message_processing_context->initialized)
    {
        Log_Warn("Message processing context (0x%x) is not initialized.", message_processing_context);
        return;
    }

    pthread_mutex_lock(&message_processing_context->mutex);
    message_processing_context->message.lastHttpStatus = http_status_code;

    // It's possible that the message has been destroy by ADUC_D2C_Messaging_Uninit().
    // In this case, we just abort here.
    if (message_processing_context->message.content == NULL)
    {
        Log_Debug("Message already been destroy. No op.");
        goto done;
    }

    // Note, stop processing the message if the responseCallback() returned false,
    // or http_status_code is >= 200 and < 300.
    bool success =
        (message_processing_context->message.responseCallback != NULL
         && !message_processing_context->message.responseCallback(http_status_code, message_processing_context))
        || ((http_status_code >= 200 && http_status_code < 300));

    time_t previousRetryTimeStamp = message_processing_context->nextRetryTimeStampEpoch;
    // Call the responseCallback to allow the message owner to make a decision whether
    // to continue trying, and specified the 'nextRetryTimestamp' if needed.
    if (success)
    {
        // The callback indicates that no retries needed.
        // We're done with this message.
        Log_Debug(
            "D2C message processed successfully (t:%d, r:%d, content:0x%x )",
            message_processing_context->type,
            message_processing_context->retries,
            message_processing_context->message.content);
        OnMessageProcessingCompleted(&message_processing_context->message, ADUC_D2C_Message_Status_Success);
        goto done;
    }

    if (message_processing_context->nextRetryTimeStampEpoch != previousRetryTimeStamp)
    {
        // It's possible that the next retry time has been set by the responseCallback(),
        // we don't need to do anything here.
        SetMessageStatus(&message_processing_context->message, ADUC_D2C_Message_Status_In_Progress);
        goto done;
    }

    if (message_processing_context->retries >= message_processing_context->retryStrategy->maxRetries)
    {
        Log_Warn(
            "Maximum attempt reached (t:%d, r:%d)",
            message_processing_context->type,
            message_processing_context->retries);
        OnMessageProcessingCompleted(
            &message_processing_context->message, ADUC_D2C_Message_Status_Max_Retries_Reached);
        goto done;
    }

    for (size_t i = 0; i < message_processing_context->retryStrategy->httpStatusRetryInfoSize; i++)
    {
        ADUC_D2C_HttpStatus_Retry_Info* info = &message_processing_context->retryStrategy->httpStatusRetryInfo[i];

        if (http_status_code >= info->httpStatusMin && http_status_code <= info->httpStatusMax)
        {
            if (message_processing_context->retries >= info->maxRetry)
            {
                Log_Warn("Max retries reached (httpStatus:%d)", http_status_code);
                OnMessageProcessingCompleted(
                    &message_processing_context->message, ADUC_D2C_Message_Status_Max_Retries_Reached);
                goto done;
            }

            if (info->retryTimestampCalcFunc == NULL)
            {
                Log_Debug("Retry timestamp calculator func is not specified. Skipped. (info #%d)", i);
                continue;
            }

            message_processing_context->retries++;
            time_t newTime = info->retryTimestampCalcFunc(
                info->additionalDelaySecs,
                message_processing_context->retries,
                message_processing_context->retryStrategy->initialDelayUnitMilliSecs,
                message_processing_context->retryStrategy->maxDelaySecs,
                message_processing_context->retryStrategy->maxJitterPercent);

            Log_Debug(
                "Will resend the message in %d second(s) (epoch:%d, t:%d, r:%d, c:0x%x)",
                newTime - message_processing_context->nextRetryTimeStampEpoch,
                newTime,
                message_processing_context->type,
                message_processing_context->retries,
                message_processing_context->message.content);
            message_processing_context->nextRetryTimeStampEpoch = newTime;
            SetMessageStatus(&message_processing_context->message, ADUC_D2C_Message_Status_In_Progress);
            goto done;
        }
    }

    if (!computed)
    {
        message_processing_context->nextRetryTimeStampEpoch +=
            (time_t)message_processing_context->retryStrategy->fallbackWaitTimeSec;
        Log_Warn(
            "Failed to calculate the next retry timestamp. Next retry in %lu seconds.",
            message_processing_context->retryStrategy->fallbackWaitTimeSec);
        SetMessageStatus(&message_processing_context->message, ADUC_D2C_Message_Status_In_Progress);
    }

done:
    pthread_mutex_unlock(&message_processing_context->mutex);
}