Add retries to demos in case of a failure. (#435)

pull/439/head
leegeth 4 years ago committed by GitHub
parent d2fcf20caf
commit 4651c46479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -107,6 +107,22 @@
*/ */
#define DEFENDER_RESPONSE_REPORT_ID_FIELD_LENGTH ( sizeof( DEFENDER_RESPONSE_REPORT_ID_FIELD ) - 1 ) #define DEFENDER_RESPONSE_REPORT_ID_FIELD_LENGTH ( sizeof( DEFENDER_RESPONSE_REPORT_ID_FIELD ) - 1 )
/**
* @brief The maximum number of times to run the loop in this demo.
*
* @note The demo loop is attempted to re-run only if it fails in an iteration.
* Once the demo loop succeeds in an iteration, the demo exits successfully.
*/
#ifndef DEFENDER_MAX_DEMO_LOOP_COUNT
#define DEFENDER_MAX_DEMO_LOOP_COUNT ( 3 )
#endif
/**
* @brief Time in ticks to wait between retries of the demo loop if
* demo loop fails.
*/
#define DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS ( pdMS_TO_TICKS( 5000U ) )
/** /**
* @brief Status values of the device defender report. * @brief Status values of the device defender report.
*/ */
@ -633,6 +649,7 @@ void prvDefenderDemoTask( void * pvParameters )
bool xStatus = false; bool xStatus = false;
BaseType_t xExitStatus = EXIT_FAILURE; BaseType_t xExitStatus = EXIT_FAILURE;
uint32_t ulReportLength = 0UL, i, ulMqttSessionEstablished = 0UL; uint32_t ulReportLength = 0UL, i, ulMqttSessionEstablished = 0UL;
UBaseType_t uxDemoRunCount = 0UL;
/* Remove compiler warnings about unused parameters. */ /* Remove compiler warnings about unused parameters. */
( void ) pvParameters; ( void ) pvParameters;
@ -643,6 +660,11 @@ void prvDefenderDemoTask( void * pvParameters )
/* Start with report not received. */ /* Start with report not received. */
xReportStatus = ReportStatusNotReceived; xReportStatus = ReportStatusNotReceived;
/* This demo runs a single loop unless there are failures in the demo execution.
* In case of failures in the demo execution, demo loop will be retried for up to
* DEFENDER_MAX_DEMO_LOOP_COUNT times. */
do
{
/* Set a report Id to be used. /* Set a report Id to be used.
* *
* !!!NOTE!!! * !!!NOTE!!!
@ -789,7 +811,7 @@ void prvDefenderDemoTask( void * pvParameters )
} }
/* Wait for sometime between consecutive executions of ProcessLoop. */ /* Wait for sometime between consecutive executions of ProcessLoop. */
vTaskDelay( 1000 / portTICK_PERIOD_MS ); vTaskDelay( pdMS_TO_TICKS( 1000U ) );
} }
} }
@ -820,11 +842,38 @@ void prvDefenderDemoTask( void * pvParameters )
&xNetworkContext ); &xNetworkContext );
} }
/****************************** Finish. ******************************/
if( ( xStatus == true ) && ( xReportStatus == ReportStatusAccepted ) ) if( ( xStatus == true ) && ( xReportStatus == ReportStatusAccepted ) )
{ {
xExitStatus = EXIT_SUCCESS; xExitStatus = EXIT_SUCCESS;
}
/*********************** Retry in case of failure. ************************/
/* Increment the demo run count. */
uxDemoRunCount++;
if( xExitStatus == EXIT_SUCCESS )
{
LogInfo( ( "Demo iteration %lu is successful.", uxDemoRunCount ) );
}
/* Attempt to retry a failed iteration of demo for up to #DEFENDER_MAX_DEMO_LOOP_COUNT times. */
else if( uxDemoRunCount < DEFENDER_MAX_DEMO_LOOP_COUNT )
{
LogWarn( ( "Demo iteration %lu failed. Retrying...", uxDemoRunCount ) );
vTaskDelay( DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS );
}
/* Failed all #DEFENDER_MAX_DEMO_LOOP_COUNT demo iterations. */
else
{
LogError( ( "All %d demo iterations failed.", DEFENDER_MAX_DEMO_LOOP_COUNT ) );
break;
}
} while( xExitStatus != EXIT_SUCCESS );
/****************************** Finish. ******************************/
if( xExitStatus == EXIT_SUCCESS )
{
LogInfo( ( "Demo completed successfully." ) ); LogInfo( ( "Demo completed successfully." ) );
} }
else else

@ -148,6 +148,55 @@
*/ */
#define SHADOW_REPORTED_JSON_LENGTH ( sizeof( SHADOW_REPORTED_JSON ) - 3 ) #define SHADOW_REPORTED_JSON_LENGTH ( sizeof( SHADOW_REPORTED_JSON ) - 3 )
/**
* @brief The maximum number of times to run the loop in this demo.
*
* @note The demo loop is attempted to re-run only if it fails in an iteration.
* Once the demo loop succeeds in an iteration, the demo exits successfully.
*/
#ifndef SHADOW_MAX_DEMO_LOOP_COUNT
#define SHADOW_MAX_DEMO_LOOP_COUNT ( 3 )
#endif
/**
* @brief Time in ticks to wait between retries of the demo loop if
* demo loop fails.
*/
#define DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS ( pdMS_TO_TICKS( 5000U ) )
/**
* @brief The maximum number of times to call MQTT_ProcessLoop() when waiting
* for a response for Shadow delete operation.
*/
#define MQTT_PROCESS_LOOP_DELETE_RESPONSE_COUNT_MAX ( 30U )
/**
* @brief Timeout for MQTT_ProcessLoop in milliseconds.
*/
#define MQTT_PROCESS_LOOP_TIMEOUT_MS ( 700U )
/**
* @brief JSON key for response code that indicates the type of error in
* the error document received on topic `/delete/rejected`.
*/
#define SHADOW_DELETE_REJECTED_ERROR_CODE_KEY "code"
/**
* @brief Length of #SHADOW_DELETE_REJECTED_ERROR_CODE_KEY.
*/
#define SHADOW_DELETE_REJECTED_ERROR_CODE_KEY_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_DELETE_REJECTED_ERROR_CODE_KEY ) - 1 ) )
/**
* @brief Error response code sent from AWS IoT Shadow service when an attempt
* is made to delete a Shadow document that doesn't exist.
*/
#define SHADOW_NO_SHADOW_EXISTS_ERROR_CODE "404"
/**
* @brief Length of #SHADOW_NO_SHADOW_EXISTS_ERROR_CODE.
*/
#define SHADOW_NO_SHADOW_EXISTS_ERROR_CODE_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_NO_SHADOW_EXISTS_ERROR_CODE ) - 1 ) )
/*------------- Demo configurations -------------------------*/ /*------------- Demo configurations -------------------------*/
#ifndef democonfigTHING_NAME #ifndef democonfigTHING_NAME
@ -225,6 +274,24 @@ static BaseType_t xUpdateDeltaReturn = pdPASS;
*/ */
static BaseType_t xUpdateAcceptedReturn = pdPASS; static BaseType_t xUpdateAcceptedReturn = pdPASS;
/**
* @brief Status of the response of Shadow delete operation from AWS IoT
* message broker.
*/
static BaseType_t xDeleteResponseReceived = pdFALSE;
/**
* @brief Status of the Shadow delete operation.
*
* The Shadow delete status will be updated by the incoming publishes on the
* MQTT topics for delete acknowledgement from AWS IoT message broker
* (accepted/rejected). Shadow document is considered to be deleted if an
* incoming publish is received on `/delete/accepted` topic or an incoming
* publish is received on `/delete/rejected` topic with error code 404. Code 404
* indicates that the Shadow document does not exist for the Thing yet.
*/
static BaseType_t xShadowDeleted = pdFALSE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/** /**
@ -271,6 +338,126 @@ static void prvUpdateAcceptedHandler( MQTTPublishInfo_t * pxPublishInfo );
*/ */
static void prvShadowDemoTask( void * pvParameters ); static void prvShadowDemoTask( void * pvParameters );
/**
* @brief Process payload from `/delete/rejected` topic.
*
* This handler examines the rejected message to look for the reject reason code.
* If the reject reason code is `404`, an attempt was made to delete a shadow
* document which was not present yet. This is considered to be success for this
* demo application.
*
* @param[in] pxPublishInfo Deserialized publish info pointer for the incoming
* packet.
*/
static void prvDeleteRejectedHandler( MQTTPublishInfo_t * pxPublishInfo );
/**
* @brief Helper function to wait for a response for Shadow delete operation.
*
* @param[in] pxMQTTContext MQTT context pointer.
*
* @return pdPASS if successfully received a response for Shadow delete
* operation; pdFAIL otherwise.
*/
static BaseType_t prvWaitForDeleteResponse( MQTTContext_t * pxMQTTContext );
/*-----------------------------------------------------------*/
static BaseType_t prvWaitForDeleteResponse( MQTTContext_t * pxMQTTContext )
{
uint8_t ucCount = 0U;
MQTTStatus_t xMQTTStatus = MQTTSuccess;
BaseType_t xReturnStatus = pdPASS;
configASSERT( pxMQTTContext != NULL );
while( ( xDeleteResponseReceived != pdTRUE ) &&
( ucCount++ < MQTT_PROCESS_LOOP_DELETE_RESPONSE_COUNT_MAX ) &&
( xMQTTStatus == MQTTSuccess ) )
{
/* Event callback will set #xDeleteResponseReceived when receiving an
* incoming publish on either `/delete/accepted` or `/delete/rejected`
* Shadow topics. */
xMQTTStatus = MQTT_ProcessLoop( pxMQTTContext, MQTT_PROCESS_LOOP_TIMEOUT_MS );
}
if( ( xMQTTStatus != MQTTSuccess ) || ( xDeleteResponseReceived != pdTRUE ) )
{
LogError( ( "MQTT_ProcessLoop failed to receive a response for Shadow delete operation:"
" LoopDuration=%u, MQTT Status=%s.",
( MQTT_PROCESS_LOOP_TIMEOUT_MS * ucCount ),
MQTT_Status_strerror( xMQTTStatus ) ) );
xReturnStatus = pdFAIL;
}
return xReturnStatus;
}
/*-----------------------------------------------------------*/
static void prvDeleteRejectedHandler( MQTTPublishInfo_t * pxPublishInfo )
{
JSONStatus_t result = JSONSuccess;
char * pcOutValue = NULL;
uint32_t ulOutValueLength = 0UL;
configASSERT( pxPublishInfo != NULL );
configASSERT( pxPublishInfo->pPayload != NULL );
LogInfo( ( "/delete/rejected json payload:%s.", ( const char * ) pxPublishInfo->pPayload ) );
/* The payload will look similar to this:
* {
* "code": error-code,
* "message": "error-message",
* "timestamp": timestamp,
* "clientToken": "token"
* }
*/
/* Make sure the payload is a valid json document. */
result = JSON_Validate( pxPublishInfo->pPayload,
pxPublishInfo->payloadLength );
if( result == JSONSuccess )
{
/* Then we start to get the version value by JSON keyword "version". */
result = JSON_SearchConst( pxPublishInfo->pPayload,
pxPublishInfo->payloadLength,
SHADOW_DELETE_REJECTED_ERROR_CODE_KEY,
SHADOW_DELETE_REJECTED_ERROR_CODE_KEY_LENGTH,
&pcOutValue,
( size_t * ) &ulOutValueLength,
NULL );
}
else
{
LogError( ( "The json document is invalid!!" ) );
}
if( result == JSONSuccess )
{
LogInfo( ( "Error code is: %.*s.",
ulOutValueLength,
pcOutValue ) );
/* Check if error code is `404`. An error code `404` indicates that an
* attempt was made to delete a Shadow document that didn't exist. */
if( ulOutValueLength == SHADOW_NO_SHADOW_EXISTS_ERROR_CODE_LENGTH )
{
if( strncmp( pcOutValue, SHADOW_NO_SHADOW_EXISTS_ERROR_CODE,
SHADOW_NO_SHADOW_EXISTS_ERROR_CODE_LENGTH ) == 0 )
{
xShadowDeleted = pdTRUE;
}
}
}
else
{
LogError( ( "No error code in json document!!" ) );
}
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvUpdateDeltaHandler( MQTTPublishInfo_t * pxPublishInfo ) static void prvUpdateDeltaHandler( MQTTPublishInfo_t * pxPublishInfo )
@ -536,6 +723,18 @@ static void prvEventCallback( MQTTContext_t * pxMqttContext,
{ {
LogInfo( ( "/update/rejected json payload:%s.", ( const char * ) pxDeserializedInfo->pPublishInfo->pPayload ) ); LogInfo( ( "/update/rejected json payload:%s.", ( const char * ) pxDeserializedInfo->pPublishInfo->pPayload ) );
} }
else if( messageType == ShadowMessageTypeDeleteAccepted )
{
LogInfo( ( "Received an MQTT incoming publish on /delete/accepted topic." ) );
xShadowDeleted = pdTRUE;
xDeleteResponseReceived = pdTRUE;
}
else if( messageType == ShadowMessageTypeDeleteRejected )
{
/* Handler function to process payload. */
prvDeleteRejectedHandler( pxDeserializedInfo->pPublishInfo );
xDeleteResponseReceived = pdTRUE;
}
else else
{ {
LogInfo( ( "Other message type:%d !!", messageType ) ); LogInfo( ( "Other message type:%d !!", messageType ) );
@ -593,7 +792,8 @@ void vStartShadowDemo( void )
*/ */
void prvShadowDemoTask( void * pvParameters ) void prvShadowDemoTask( void * pvParameters )
{ {
BaseType_t demoStatus = pdPASS; BaseType_t xDemoStatus = pdPASS;
UBaseType_t uxDemoRunCount = 0UL;
/* A buffer containing the update document. It has static duration to prevent /* A buffer containing the update document. It has static duration to prevent
* it from being placed on the call stack. */ * it from being placed on the call stack. */
@ -607,50 +807,113 @@ void prvShadowDemoTask( void * pvParameters )
/****************************** Connect. ******************************/ /****************************** Connect. ******************************/
demoStatus = xEstablishMqttSession( &xMqttContext, /* This demo runs a single loop unless there are failures in the demo execution.
* In case of failures in the demo execution, demo loop will be retried for up to
* SHADOW_MAX_DEMO_LOOP_COUNT times. */
do
{
/****************************** Connect. ******************************/
xDemoStatus = xEstablishMqttSession( &xMqttContext,
&xNetworkContext, &xNetworkContext,
&xBuffer, &xBuffer,
prvEventCallback ); prvEventCallback );
if( demoStatus == pdFAIL ) if( xDemoStatus == pdFAIL )
{ {
/* Log error to indicate connection failure. */ /* Log error to indicate connection failure. */
LogError( ( "Failed to connect to MQTT broker." ) ); LogError( ( "Failed to connect to MQTT broker." ) );
} }
if( demoStatus == pdPASS ) /**************** Attempt to delete Shadow document. ******************/
if( xDemoStatus == pdPASS )
{
/* Reset the shadow delete status flags. */
xDeleteResponseReceived = pdFALSE;
xShadowDeleted = pdFALSE;
/* First of all, try to delete any Shadow document in the cloud.
* Try to subscribe to `/delete/accepted` and `/delete/rejected` topics. */
xDemoStatus = xSubscribeToTopic( &xMqttContext,
SHADOW_TOPIC_STRING_DELETE_ACCEPTED( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED( THING_NAME_LENGTH ) );
}
if( xDemoStatus == pdPASS )
{ {
/* Try to delete any Shadow document in the cloud. This is done to /* Try to subscribe to `/delete/rejected` topic. */
* ensure possbile previous Shadow documents do not affect the state xDemoStatus = xSubscribeToTopic( &xMqttContext,
* expected in the current demo. */ SHADOW_TOPIC_STRING_DELETE_REJECTED( democonfigTHING_NAME ),
demoStatus = xPublishToTopic( &xMqttContext, SHADOW_TOPIC_LENGTH_DELETE_REJECTED( THING_NAME_LENGTH ) );
}
if( xDemoStatus == pdPASS )
{
/* Publish to Shadow `delete` topic to attempt to delete the
* Shadow document if exists. */
xDemoStatus = xPublishToTopic( &xMqttContext,
SHADOW_TOPIC_STRING_DELETE( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_DELETE( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_DELETE( THING_NAME_LENGTH ), SHADOW_TOPIC_LENGTH_DELETE( THING_NAME_LENGTH ),
pcUpdateDocument, pcUpdateDocument,
0U ); 0U );
} }
/* Wait for an incoming publish on `/delete/accepted` or `/delete/rejected`
* topics, if not already received a publish. */
if( ( xDemoStatus == pdPASS ) && ( xDeleteResponseReceived != pdTRUE ) )
{
xDemoStatus = prvWaitForDeleteResponse( &xMqttContext );
}
/* Unsubscribe from the `/delete/accepted` and 'delete/rejected` topics.*/
if( xDemoStatus == pdPASS )
{
xDemoStatus = xUnsubscribeFromTopic( &xMqttContext,
SHADOW_TOPIC_STRING_DELETE_ACCEPTED( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_DELETE_ACCEPTED( THING_NAME_LENGTH ) );
}
if( xDemoStatus == pdPASS )
{
xDemoStatus = xUnsubscribeFromTopic( &xMqttContext,
SHADOW_TOPIC_STRING_DELETE_REJECTED( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_DELETE_REJECTED( THING_NAME_LENGTH ) );
}
/* Check if Shadow document delete was successful. A delete can be
* successful in cases listed below.
* 1. If an incoming publish is received on `/delete/accepted` topic.
* 2. If an incoming publish is received on `/delete/rejected` topic
* with error code 404. This indicates that a Shadow document was
* not present for the Thing. */
if( xShadowDeleted == pdFALSE )
{
LogError( ( "Shadow delete operation failed." ) );
xDemoStatus = pdFAIL;
}
/********************* Subscribe to Shadow topics. ************************/ /********************* Subscribe to Shadow topics. ************************/
/* Then try to subscribe the Shadow topics. */ /* Then try to subscribe the Shadow topics. */
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
demoStatus = xSubscribeToTopic( &xMqttContext, xDemoStatus = xSubscribeToTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE_DELTA( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE_DELTA( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE_DELTA( THING_NAME_LENGTH ) ); SHADOW_TOPIC_LENGTH_UPDATE_DELTA( THING_NAME_LENGTH ) );
} }
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
demoStatus = xSubscribeToTopic( &xMqttContext, xDemoStatus = xSubscribeToTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( THING_NAME_LENGTH ) ); SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( THING_NAME_LENGTH ) );
} }
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
demoStatus = xSubscribeToTopic( &xMqttContext, xDemoStatus = xSubscribeToTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE_REJECTED( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE_REJECTED( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( THING_NAME_LENGTH ) ); SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( THING_NAME_LENGTH ) );
} }
@ -689,7 +952,7 @@ void prvShadowDemoTask( void * pvParameters )
* the device itself. But for the purpose of making this demo self-contained, * the device itself. But for the purpose of making this demo self-contained,
* we publish one here so that we can receive a delta message later. * we publish one here so that we can receive a delta message later.
*/ */
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
/* Desired power on state . */ /* Desired power on state . */
LogInfo( ( "Send desired power state with 1." ) ); LogInfo( ( "Send desired power state with 1." ) );
@ -704,14 +967,14 @@ void prvShadowDemoTask( void * pvParameters )
( int ) 1, ( int ) 1,
( long unsigned ) ( xTaskGetTickCount() % 1000000 ) ); ( long unsigned ) ( xTaskGetTickCount() % 1000000 ) );
demoStatus = xPublishToTopic( &xMqttContext, xDemoStatus = xPublishToTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE( THING_NAME_LENGTH ), SHADOW_TOPIC_LENGTH_UPDATE( THING_NAME_LENGTH ),
pcUpdateDocument, pcUpdateDocument,
( SHADOW_DESIRED_JSON_LENGTH + 1 ) ); ( SHADOW_DESIRED_JSON_LENGTH + 1 ) );
} }
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
/* Note that PublishToTopic already called MQTT_ProcessLoop, /* Note that PublishToTopic already called MQTT_ProcessLoop,
* therefore responses may have been received and the prvEventCallback * therefore responses may have been received and the prvEventCallback
@ -737,7 +1000,7 @@ void prvShadowDemoTask( void * pvParameters )
( int ) ulCurrentPowerOnState, ( int ) ulCurrentPowerOnState,
( long unsigned ) ulClientToken ); ( long unsigned ) ulClientToken );
demoStatus = xPublishToTopic( &xMqttContext, xDemoStatus = xPublishToTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE( THING_NAME_LENGTH ), SHADOW_TOPIC_LENGTH_UPDATE( THING_NAME_LENGTH ),
pcUpdateDocument, pcUpdateDocument,
@ -751,41 +1014,41 @@ void prvShadowDemoTask( void * pvParameters )
/****************** Unsubscribe from Shadow topics. *******************/ /****************** Unsubscribe from Shadow topics. *******************/
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
LogInfo( ( "Start to unsubscribe shadow topics and disconnect from MQTT. \r\n" ) ); LogInfo( ( "Start to unsubscribe shadow topics and disconnect from MQTT. \r\n" ) );
demoStatus = xUnsubscribeFromTopic( &xMqttContext, xDemoStatus = xUnsubscribeFromTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE_DELTA( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE_DELTA( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE_DELTA( THING_NAME_LENGTH ) ); SHADOW_TOPIC_LENGTH_UPDATE_DELTA( THING_NAME_LENGTH ) );
if( demoStatus != pdPASS ) if( xDemoStatus != pdPASS )
{ {
LogError( ( "Failed to unsubscribe the topic %s", LogError( ( "Failed to unsubscribe the topic %s",
SHADOW_TOPIC_STRING_UPDATE_DELTA( democonfigTHING_NAME ) ) ); SHADOW_TOPIC_STRING_UPDATE_DELTA( democonfigTHING_NAME ) ) );
} }
} }
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
demoStatus = xUnsubscribeFromTopic( &xMqttContext, xDemoStatus = xUnsubscribeFromTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( THING_NAME_LENGTH ) ); SHADOW_TOPIC_LENGTH_UPDATE_ACCEPTED( THING_NAME_LENGTH ) );
if( demoStatus != pdPASS ) if( xDemoStatus != pdPASS )
{ {
LogError( ( "Failed to unsubscribe the topic %s", LogError( ( "Failed to unsubscribe the topic %s",
SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( democonfigTHING_NAME ) ) ); SHADOW_TOPIC_STRING_UPDATE_ACCEPTED( democonfigTHING_NAME ) ) );
} }
} }
if( demoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
demoStatus = xUnsubscribeFromTopic( &xMqttContext, xDemoStatus = xUnsubscribeFromTopic( &xMqttContext,
SHADOW_TOPIC_STRING_UPDATE_REJECTED( democonfigTHING_NAME ), SHADOW_TOPIC_STRING_UPDATE_REJECTED( democonfigTHING_NAME ),
SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( THING_NAME_LENGTH ) ); SHADOW_TOPIC_LENGTH_UPDATE_REJECTED( THING_NAME_LENGTH ) );
if( demoStatus != pdPASS ) if( xDemoStatus != pdPASS )
{ {
LogError( ( "Failed to unsubscribe the topic %s", LogError( ( "Failed to unsubscribe the topic %s",
SHADOW_TOPIC_STRING_UPDATE_REJECTED( democonfigTHING_NAME ) ) ); SHADOW_TOPIC_STRING_UPDATE_REJECTED( democonfigTHING_NAME ) ) );
@ -795,7 +1058,7 @@ void prvShadowDemoTask( void * pvParameters )
/****************************** Disconnect. *******************************/ /****************************** Disconnect. *******************************/
/* The MQTT session is always disconnected, even if there were prior failures. */ /* The MQTT session is always disconnected, even if there were prior failures. */
demoStatus = xDisconnectMqttSession( &xMqttContext, &xNetworkContext ); xDemoStatus = xDisconnectMqttSession( &xMqttContext, &xNetworkContext );
/* This demo performs only Device Shadow operations. If matching the Shadow /* This demo performs only Device Shadow operations. If matching the Shadow
* MQTT topic fails or there are failure in parsing the received JSON document, * MQTT topic fails or there are failure in parsing the received JSON document,
@ -805,7 +1068,30 @@ void prvShadowDemoTask( void * pvParameters )
LogError( ( "Callback function failed." ) ); LogError( ( "Callback function failed." ) );
} }
if( demoStatus == pdPASS ) /*********************** Retry in case of failure. ************************/
/* Increment the demo run count. */
uxDemoRunCount++;
if( xDemoStatus == pdPASS )
{
LogInfo( ( "Demo iteration %lu is successful.", uxDemoRunCount ) );
}
/* Attempt to retry a failed iteration of demo for up to #SHADOW_MAX_DEMO_LOOP_COUNT times. */
else if( uxDemoRunCount < SHADOW_MAX_DEMO_LOOP_COUNT )
{
LogWarn( ( "Demo iteration %lu failed. Retrying...", uxDemoRunCount ) );
vTaskDelay( DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS );
}
/* Failed all #SHADOW_MAX_DEMO_LOOP_COUNT demo iterations. */
else
{
LogError( ( "All %d demo iterations failed.", SHADOW_MAX_DEMO_LOOP_COUNT ) );
break;
}
} while( xDemoStatus != pdPASS );
if( xDemoStatus == pdPASS )
{ {
LogInfo( ( "Demo completed successfully." ) ); LogInfo( ( "Demo completed successfully." ) );
} }

@ -208,6 +208,22 @@
*/ */
#define MAKE_STATUS_REPORT( x ) "{\"status\":\"" x "\"}" #define MAKE_STATUS_REPORT( x ) "{\"status\":\"" x "\"}"
/**
* @brief The maximum number of times to run the loop in this demo.
*
* @note The demo loop is attempted to re-run only if it fails in an iteration.
* Once the demo loop succeeds in an iteration, the demo exits successfully.
*/
#ifndef JOBS_MAX_DEMO_LOOP_COUNT
#define JOBS_MAX_DEMO_LOOP_COUNT ( 3 )
#endif
/**
* @brief Time in ticks to wait between retries of the demo loop if
* demo loop fails.
*/
#define DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS ( pdMS_TO_TICKS( 5000U ) )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/** /**
@ -735,6 +751,8 @@ void vStartJobsDemo( void )
void prvJobsDemoTask( void * pvParameters ) void prvJobsDemoTask( void * pvParameters )
{ {
BaseType_t xDemoStatus = pdPASS; BaseType_t xDemoStatus = pdPASS;
UBaseType_t uxDemoRunCount = 0UL;
BaseType_t retryDemoLoop = pdFALSE;
/* Remove compiler warnings about unused parameters. */ /* Remove compiler warnings about unused parameters. */
( void ) pvParameters; ( void ) pvParameters;
@ -742,6 +760,11 @@ void prvJobsDemoTask( void * pvParameters )
/* Set the pParams member of the network context with desired transport. */ /* Set the pParams member of the network context with desired transport. */
xNetworkContext.pParams = &xTlsTransportParams; xNetworkContext.pParams = &xTlsTransportParams;
/* This demo runs a single loop unless there are failures in the demo execution.
* In case of failures in the demo execution, demo loop will be retried for up to
* JOBS_MAX_DEMO_LOOP_COUNT times. */
do
{
/* Establish an MQTT connection with AWS IoT over a mutually authenticated TLS session. */ /* Establish an MQTT connection with AWS IoT over a mutually authenticated TLS session. */
xDemoStatus = xEstablishMqttSession( &xMqttContext, xDemoStatus = xEstablishMqttSession( &xMqttContext,
&xNetworkContext, &xNetworkContext,
@ -839,12 +862,39 @@ void prvJobsDemoTask( void * pvParameters )
} }
} }
/* Increment the demo run count. */
uxDemoRunCount++;
/* Retry demo loop only if there is a failure before completing
* the processing of any pending jobs. Any failure in MQTT unsubscribe
* or disconnect is considered a failure in demo execution and retry
* will not be attempted since a retry without any pending jobs will
* make this demo indefinitely wait. */
if( ( xDemoStatus == pdFAIL ) || ( xDemoEncounteredError == pdTRUE ) )
{
if( uxDemoRunCount < JOBS_MAX_DEMO_LOOP_COUNT )
{
LogWarn( ( "Demo iteration %lu failed. Retrying...", uxDemoRunCount ) );
retryDemoLoop = pdTRUE;
}
else
{
LogError( ( "All %d demo iterations failed.", JOBS_MAX_DEMO_LOOP_COUNT ) );
retryDemoLoop = pdFALSE;
}
}
else
{
/* Reset the flag for demo retry. */
retryDemoLoop = pdFALSE;
}
/* Unsubscribe from the NextJobExecutionChanged API topic. */ /* Unsubscribe from the NextJobExecutionChanged API topic. */
if( xUnsubscribeFromTopic( &xMqttContext, if( xUnsubscribeFromTopic( &xMqttContext,
NEXT_JOB_EXECUTION_CHANGED_TOPIC( democonfigTHING_NAME ), NEXT_JOB_EXECUTION_CHANGED_TOPIC( democonfigTHING_NAME ),
sizeof( NEXT_JOB_EXECUTION_CHANGED_TOPIC( democonfigTHING_NAME ) ) - 1 ) != pdPASS ) sizeof( NEXT_JOB_EXECUTION_CHANGED_TOPIC( democonfigTHING_NAME ) ) - 1 ) != pdPASS )
{ {
xDemoStatus == pdFAIL; xDemoStatus = pdFAIL;
LogError( ( "Failed to subscribe unsubscribe from the NextJobExecutionChanged API of AWS IoT Jobs service: " LogError( ( "Failed to subscribe unsubscribe from the NextJobExecutionChanged API of AWS IoT Jobs service: "
"Topic=%s", NEXT_JOB_EXECUTION_CHANGED_TOPIC( democonfigTHING_NAME ) ) ); "Topic=%s", NEXT_JOB_EXECUTION_CHANGED_TOPIC( democonfigTHING_NAME ) ) );
} }
@ -852,9 +902,21 @@ void prvJobsDemoTask( void * pvParameters )
/* Disconnect the MQTT and network connections with AWS IoT. */ /* Disconnect the MQTT and network connections with AWS IoT. */
if( xDisconnectMqttSession( &xMqttContext, &xNetworkContext ) != pdPASS ) if( xDisconnectMqttSession( &xMqttContext, &xNetworkContext ) != pdPASS )
{ {
xDemoStatus == pdFAIL; xDemoStatus = pdFAIL;
LogError( ( "Disconnection from AWS Iot failed..." ) ); LogError( ( "Disconnection from AWS IoT failed..." ) );
}
/* Add a delay if a retry is required. */
if( retryDemoLoop == pdTRUE )
{
/* Clear the flag that indicates that indicates the demo error
* before attempting a retry. */
xDemoEncounteredError = pdFALSE;
LogInfo( ( "A short delay before the next demo iteration." ) );
vTaskDelay( DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS );
} }
} while( retryDemoLoop == pdTRUE );
if( ( xDemoEncounteredError == pdFALSE ) && ( xDemoStatus == pdPASS ) ) if( ( xDemoEncounteredError == pdFALSE ) && ( xDemoStatus == pdPASS ) )
{ {

@ -128,6 +128,22 @@ struct NetworkContext
TlsTransportParams_t * pParams; TlsTransportParams_t * pParams;
}; };
/**
* @brief The maximum number of times to run the loop in this demo.
*
* @note The demo loop is attempted to re-run only if it fails in an iteration.
* Once the demo loop succeeds in an iteration, the demo exits successfully.
*/
#ifndef HTTP_MAX_DEMO_LOOP_COUNT
#define HTTP_MAX_DEMO_LOOP_COUNT ( 3 )
#endif
/**
* @brief Time in ticks to wait between retries of the demo loop if
* demo loop fails.
*/
#define DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS ( pdMS_TO_TICKS( 5000U ) )
/** /**
* @brief A buffer used in the demo for storing HTTP request headers and * @brief A buffer used in the demo for storing HTTP request headers and
* HTTP response headers and body. * HTTP response headers and body.
@ -215,6 +231,7 @@ static void prvHTTPDemoTask( void * pvParameters )
NetworkContext_t xNetworkContext = { 0 }; NetworkContext_t xNetworkContext = { 0 };
TlsTransportParams_t xTlsTransportParams = { 0 }; TlsTransportParams_t xTlsTransportParams = { 0 };
BaseType_t xIsConnectionEstablished = pdFALSE; BaseType_t xIsConnectionEstablished = pdFALSE;
UBaseType_t uxDemoRunCount = 0UL;
/* The user of this demo must check the logs for any failure codes. */ /* The user of this demo must check the logs for any failure codes. */
BaseType_t xDemoStatus = pdPASS; BaseType_t xDemoStatus = pdPASS;
@ -225,6 +242,11 @@ static void prvHTTPDemoTask( void * pvParameters )
/* Set the pParams member of the network context with desired transport. */ /* Set the pParams member of the network context with desired transport. */
xNetworkContext.pParams = &xTlsTransportParams; xNetworkContext.pParams = &xTlsTransportParams;
/* This demo runs a single loop unless there are failures in the demo execution.
* In case of failures in the demo execution, demo loop will be retried for up to
* HTTP_MAX_DEMO_LOOP_COUNT times. */
do
{
/**************************** Connect. ******************************/ /**************************** Connect. ******************************/
/* Attempt to connect to the HTTP server. If connection fails, retry after a /* Attempt to connect to the HTTP server. If connection fails, retry after a
@ -275,6 +297,29 @@ static void prvHTTPDemoTask( void * pvParameters )
TLS_FreeRTOS_Disconnect( &xNetworkContext ); TLS_FreeRTOS_Disconnect( &xNetworkContext );
} }
/*********************** Retry in case of failure. ************************/
/* Increment the demo run count. */
uxDemoRunCount++;
if( xDemoStatus == pdPASS )
{
LogInfo( ( "Demo iteration %lu was successful.", uxDemoRunCount ) );
}
/* Attempt to retry a failed demo iteration for up to #HTTP_MAX_DEMO_LOOP_COUNT times. */
else if( uxDemoRunCount < HTTP_MAX_DEMO_LOOP_COUNT )
{
LogWarn( ( "Demo iteration %lu failed. Retrying...", uxDemoRunCount ) );
vTaskDelay( DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS );
}
/* Failed all #HTTP_MAX_DEMO_LOOP_COUNT demo iterations. */
else
{
LogError( ( "All %d demo iterations failed.", HTTP_MAX_DEMO_LOOP_COUNT ) );
break;
}
} while( xDemoStatus != pdPASS );
if( xDemoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
LogInfo( ( "prvHTTPDemoTask() completed successfully. " LogInfo( ( "prvHTTPDemoTask() completed successfully. "

@ -170,6 +170,22 @@ struct NetworkContext
PlaintextTransportParams_t * pParams; PlaintextTransportParams_t * pParams;
}; };
/**
* @brief The maximum number of times to run the loop in this demo.
*
* @note The demo loop is attempted to re-run only if it fails in an iteration.
* Once the demo loop succeeds in an iteration, the demo exits successfully.
*/
#ifndef HTTP_MAX_DEMO_LOOP_COUNT
#define HTTP_MAX_DEMO_LOOP_COUNT ( 3 )
#endif
/**
* @brief Time in ticks to wait between retries of the demo loop if
* demo loop fails.
*/
#define DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS ( pdMS_TO_TICKS( 5000U ) )
/** /**
* @brief A pair containing a path string of the URI and its length. * @brief A pair containing a path string of the URI and its length.
*/ */
@ -294,6 +310,7 @@ static void prvHTTPDemoTask( void * pvParameters )
}; };
BaseType_t xIsConnectionEstablished = pdFALSE; BaseType_t xIsConnectionEstablished = pdFALSE;
UBaseType_t uxHttpPathCount = 0U; UBaseType_t uxHttpPathCount = 0U;
UBaseType_t uxDemoRunCount = 0UL;
/* The user of this demo must check the logs for any failure codes. */ /* The user of this demo must check the logs for any failure codes. */
BaseType_t xDemoStatus = pdPASS; BaseType_t xDemoStatus = pdPASS;
@ -304,6 +321,11 @@ static void prvHTTPDemoTask( void * pvParameters )
/* Set the pParams member of the network context with desired transport. */ /* Set the pParams member of the network context with desired transport. */
xNetworkContext.pParams = &xPlaintextTransportParams; xNetworkContext.pParams = &xPlaintextTransportParams;
/* This demo runs a single loop unless there are failures in the demo execution.
* In case of failures in the demo execution, demo loop will be retried for up to
* HTTP_MAX_DEMO_LOOP_COUNT times. */
do
{
/**************************** Connect. ******************************/ /**************************** Connect. ******************************/
/* Attempt to connect to the HTTP server. If connection fails, retry after a /* Attempt to connect to the HTTP server. If connection fails, retry after a
@ -361,6 +383,29 @@ static void prvHTTPDemoTask( void * pvParameters )
Plaintext_FreeRTOS_Disconnect( &xNetworkContext ); Plaintext_FreeRTOS_Disconnect( &xNetworkContext );
} }
/*********************** Retry in case of failure. ************************/
/* Increment the demo run count. */
uxDemoRunCount++;
if( xDemoStatus == pdPASS )
{
LogInfo( ( "Demo iteration %lu was successful.", uxDemoRunCount ) );
}
/* Attempt to retry a failed demo iteration for up to #HTTP_MAX_DEMO_LOOP_COUNT times. */
else if( uxDemoRunCount < HTTP_MAX_DEMO_LOOP_COUNT )
{
LogWarn( ( "Demo iteration %lu failed. Retrying...", uxDemoRunCount ) );
vTaskDelay( DELAY_BETWEEN_DEMO_RETRY_ITERATIONS_TICKS );
}
/* Failed all #HTTP_MAX_DEMO_LOOP_COUNT demo iterations. */
else
{
LogError( ( "All %d demo iterations failed.", HTTP_MAX_DEMO_LOOP_COUNT ) );
break;
}
} while( xDemoStatus != pdPASS );
if( xDemoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
LogInfo( ( "prvHTTPDemoTask() completed successfully. " LogInfo( ( "prvHTTPDemoTask() completed successfully. "

@ -1 +1 @@
Subproject commit 5bfadf5f86a038986ebdf7114939d73de2681f7f Subproject commit c3ed2a23a64390178f6332589aac6994cb944f48
Loading…
Cancel
Save