Skip to content

Commit 74b18b0

Browse files
kateyanuraghassanctechjdelapladisa6302
authored
Adding error handler in PIC state machine and updating client/stream state machines to use the error handler on state transitions (#143)
* The commit includes following - (1) Refactoring Exponential backoff utility by changing name(s) to use 'RetryStrategy' (2) Minor logging improvements in Exponential backoff utility (3) Adding KVS retry strategy and related callbacks to be used in client and streams (4) Adding a new error handler in PIC state machine (5) Updating KVS client and stream state machines to use PIC error handler and exponential backoff retry strategy on encountering error while state transitions * - Adding client callback to get retry strategy. This is particularly needed for unit testing - Addressing PR feedback * - Updating UTs to handle memory leak for offline streaming - Addressing PR feedback * Addressing PR feedback * Update Client.c trigger travis CI * All events will have a unique L1 TAGS. (#145) * Events mkv size bug (#144) * committing to test out changes, added ability to increment the size of tags after appending additional SimpleTags * updating logs * tagsStart initialization was incorrect * cleanup debug logs * Unit test and clang sanitization * accidental leftover comment forward slash * Memory leak in unit test * Removing if else that doesn't cover existing cases * Unnecessary setting of variables that will not be used past this point in the function Co-authored-by: Hassan Sahibzada <[email protected]> * Log git hash Co-authored-by: Hassan Sahibzada <[email protected]> Co-authored-by: jdelapla <[email protected]> Co-authored-by: Divya Sampath Kumar <[email protected]>
1 parent 7ffa1f0 commit 74b18b0

File tree

20 files changed

+1058
-384
lines changed

20 files changed

+1058
-384
lines changed

src/client/include/com/amazonaws/kinesis/video/client/Include.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,21 @@ struct __StorageInfo {
11141114

11151115
typedef struct __StorageInfo* PStorageInfo;
11161116

1117+
/**
1118+
* Function to create a retry strategy to be used for the client and streams
1119+
* on detecting errors from service API calls. The retry strategy is a part of
1120+
* client struct.
1121+
*
1122+
* NOTE: This is an optional callback. If not specified, the SDK will use
1123+
* default retry strategy. Unless there is no specific use case, it is
1124+
* recommended to leave this callback NULL and let SDK handle the retries.
1125+
*
1126+
* @param 1 CLIENT_HANDLE - IN - The client handle.
1127+
*
1128+
* @return Status of the callback
1129+
*/
1130+
typedef STATUS (*GetKvsRetryStrategyFn)(CLIENT_HANDLE);
1131+
11171132
/**
11181133
* Client Info
11191134
*/
@@ -1152,6 +1167,12 @@ typedef struct __ClientInfo {
11521167
// period (in hundreds of nanos) at which callback will be fired to check stream
11531168
// clients should set this value to 0.
11541169
UINT64 reservedCallbackPeriod;
1170+
1171+
// Retry strategy for the client and all the streams under it
1172+
KvsRetryStrategy kvsRetryStrategy;
1173+
1174+
// Function pointer for application to provide a custom retry strategy
1175+
GetKvsRetryStrategyFn getKvsRetryStrategyFn;
11551176
} ClientInfo, *PClientInfo;
11561177

11571178
/**

src/client/src/Client.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ STATUS checkIntermittentProducerCallback(UINT32 timerId, UINT64 currentTime, UIN
8383
}
8484
}
8585
}
86-
8786
pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.streamListLock);
8887
}
8988

@@ -94,6 +93,67 @@ STATUS checkIntermittentProducerCallback(UINT32 timerId, UINT64 currentTime, UIN
9493
return retStatus;
9594
}
9695

96+
STATUS setupDefaultKvsRetryStrategy(PKinesisVideoClient pKinesisVideoClient) {
97+
ENTERS();
98+
STATUS retStatus = STATUS_SUCCESS;
99+
100+
// Use default as exponential backoff wait
101+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.createRetryStrategyFn = exponentialBackoffRetryStrategyCreate;
102+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.freeRetryStrategyFn = exponentialBackoffRetryStrategyFree;
103+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.executeRetryStrategyFn = getExponentialBackoffRetryStrategyWaitTime;
104+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.retryStrategyType = KVS_RETRY_STRATEGY_EXPONENTIAL_BACKOFF_WAIT;
105+
106+
CleanUp:
107+
LEAVES();
108+
return retStatus;
109+
}
110+
111+
STATUS configureClientWithRetryStrategy(PKinesisVideoClient pKinesisVideoClient) {
112+
ENTERS();
113+
PRetryStrategy pRetryStrategy = NULL;
114+
STATUS retStatus = STATUS_SUCCESS;
115+
KVS_RETRY_STRATEGY_TYPE defaultKvsRetryStrategyType = KVS_RETRY_STRATEGY_EXPONENTIAL_BACKOFF_WAIT;
116+
117+
CHK(pKinesisVideoClient != NULL, STATUS_NULL_ARG);
118+
119+
// If the callbacks for retry strategy are already set, then use that otherwise
120+
// build the client with a default retry strategy.
121+
if (pKinesisVideoClient->deviceInfo.clientInfo.getKvsRetryStrategyFn != NULL) {
122+
CHK_STATUS(pKinesisVideoClient->deviceInfo.clientInfo.getKvsRetryStrategyFn(TO_CLIENT_HANDLE(pKinesisVideoClient)));
123+
} else {
124+
CHK_STATUS(setupDefaultKvsRetryStrategy(pKinesisVideoClient));
125+
}
126+
127+
if (pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.createRetryStrategyFn != NULL) {
128+
CHK_STATUS(pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.createRetryStrategyFn(
129+
NULL /* use default retry strategy configuration */, &pRetryStrategy));
130+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.pRetryStrategy = pRetryStrategy;
131+
}
132+
133+
CleanUp:
134+
135+
LEAVES();
136+
return retStatus;
137+
}
138+
139+
STATUS freeClientRetryStrategy(PKinesisVideoClient pKinesisVideoClient) {
140+
ENTERS();
141+
STATUS retStatus = STATUS_SUCCESS;
142+
143+
CHK(pKinesisVideoClient != NULL &&
144+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.pRetryStrategy != NULL &&
145+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.freeRetryStrategyFn != NULL, STATUS_SUCCESS);
146+
147+
CHK_STATUS(pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.freeRetryStrategyFn(
148+
&(pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.pRetryStrategy)));
149+
pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy.pRetryStrategy = NULL;
150+
151+
CleanUp:
152+
153+
LEAVES();
154+
return retStatus;
155+
}
156+
97157
/**
98158
* Creates a client
99159
*/
@@ -158,6 +218,8 @@ STATUS createKinesisVideoClient(PDeviceInfo pDeviceInfo, PClientCallbacks pClien
158218
// Copy the structures in their entirety
159219
MEMCPY(&pKinesisVideoClient->clientCallbacks, pClientCallbacks, SIZEOF(ClientCallbacks));
160220

221+
CHK_STATUS(configureClientWithRetryStrategy(pKinesisVideoClient));
222+
161223
// Fix-up the defaults if needed
162224
// IMPORTANT!!! The calloc allocator will zero the memory which will also act as a
163225
// sentinel value in case of an earlier version of the structure
@@ -1613,6 +1675,9 @@ STATUS freeKinesisVideoClientInternal(PKinesisVideoClient pKinesisVideoClient, S
16131675
gKinesisVideoClient = NULL;
16141676
}
16151677

1678+
// Free retry strategy
1679+
freeClientRetryStrategy(pKinesisVideoClient);
1680+
16161681
// Release the heap
16171682
if (pKinesisVideoClient->pHeap) {
16181683
heapDebugCheckAllocator(pKinesisVideoClient->pHeap, TRUE);

src/client/src/ClientState.c

Lines changed: 97 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,107 @@
99
* Static definitions of the states
1010
*/
1111
StateMachineState CLIENT_STATE_MACHINE_STATES[] = {
12-
{CLIENT_STATE_NEW, CLIENT_STATE_NONE | CLIENT_STATE_NEW, fromNewClientState, executeNewClientState, INFINITE_RETRY_COUNT_SENTINEL,
13-
STATUS_INVALID_CLIENT_READY_STATE},
14-
{CLIENT_STATE_AUTH, CLIENT_STATE_READY | CLIENT_STATE_NEW | CLIENT_STATE_AUTH, fromAuthClientState, executeAuthClientState,
15-
SERVICE_CALL_MAX_RETRY_COUNT, STATUS_CLIENT_AUTH_CALL_FAILED},
16-
{CLIENT_STATE_GET_TOKEN, CLIENT_STATE_AUTH | CLIENT_STATE_PROVISION | CLIENT_STATE_GET_TOKEN, fromGetTokenClientState, executeGetTokenClientState,
17-
SERVICE_CALL_MAX_RETRY_COUNT, STATUS_GET_CLIENT_TOKEN_CALL_FAILED},
18-
{CLIENT_STATE_PROVISION, CLIENT_STATE_AUTH | CLIENT_STATE_PROVISION, fromProvisionClientState, executeProvisionClientState,
19-
SERVICE_CALL_MAX_RETRY_COUNT, STATUS_CLIENT_PROVISION_CALL_FAILED},
20-
{CLIENT_STATE_CREATE, CLIENT_STATE_PROVISION | CLIENT_STATE_GET_TOKEN | CLIENT_STATE_AUTH | CLIENT_STATE_CREATE, fromCreateClientState,
21-
executeCreateClientState, SERVICE_CALL_MAX_RETRY_COUNT, STATUS_CREATE_CLIENT_CALL_FAILED},
22-
{CLIENT_STATE_TAG_CLIENT, CLIENT_STATE_CREATE | CLIENT_STATE_TAG_CLIENT | CLIENT_STATE_READY, fromTagClientState, executeTagClientState,
23-
SERVICE_CALL_MAX_RETRY_COUNT, STATUS_TAG_CLIENT_CALL_FAILED},
24-
{CLIENT_STATE_READY, CLIENT_STATE_GET_TOKEN | CLIENT_STATE_AUTH | CLIENT_STATE_TAG_CLIENT | CLIENT_STATE_CREATE | CLIENT_STATE_READY,
25-
fromReadyClientState, executeReadyClientState, INFINITE_RETRY_COUNT_SENTINEL, STATUS_CLIENT_READY_CALLBACK_FAILED},
12+
{
13+
CLIENT_STATE_NEW,
14+
CLIENT_STATE_NONE | CLIENT_STATE_NEW,
15+
fromNewClientState,
16+
executeNewClientState,
17+
defaultClientStateTransitionHook,
18+
INFINITE_RETRY_COUNT_SENTINEL,
19+
STATUS_INVALID_CLIENT_READY_STATE
20+
},
21+
{
22+
CLIENT_STATE_AUTH,
23+
CLIENT_STATE_READY | CLIENT_STATE_NEW | CLIENT_STATE_AUTH,
24+
fromAuthClientState,
25+
executeAuthClientState,
26+
defaultClientStateTransitionHook,
27+
SERVICE_CALL_MAX_RETRY_COUNT,
28+
STATUS_CLIENT_AUTH_CALL_FAILED
29+
},
30+
{
31+
CLIENT_STATE_GET_TOKEN,
32+
CLIENT_STATE_AUTH | CLIENT_STATE_PROVISION | CLIENT_STATE_GET_TOKEN,
33+
fromGetTokenClientState,
34+
executeGetTokenClientState,
35+
defaultClientStateTransitionHook,
36+
SERVICE_CALL_MAX_RETRY_COUNT,
37+
STATUS_GET_CLIENT_TOKEN_CALL_FAILED
38+
},
39+
{
40+
CLIENT_STATE_PROVISION,
41+
CLIENT_STATE_AUTH | CLIENT_STATE_PROVISION,
42+
fromProvisionClientState,
43+
executeProvisionClientState,
44+
defaultClientStateTransitionHook,
45+
SERVICE_CALL_MAX_RETRY_COUNT,
46+
STATUS_CLIENT_PROVISION_CALL_FAILED
47+
},
48+
{
49+
CLIENT_STATE_CREATE,
50+
CLIENT_STATE_PROVISION | CLIENT_STATE_GET_TOKEN | CLIENT_STATE_AUTH | CLIENT_STATE_CREATE,
51+
fromCreateClientState,
52+
executeCreateClientState,
53+
defaultClientStateTransitionHook,
54+
SERVICE_CALL_MAX_RETRY_COUNT,
55+
STATUS_CREATE_CLIENT_CALL_FAILED
56+
},
57+
{
58+
CLIENT_STATE_TAG_CLIENT,
59+
CLIENT_STATE_CREATE | CLIENT_STATE_TAG_CLIENT | CLIENT_STATE_READY,
60+
fromTagClientState,
61+
executeTagClientState,
62+
defaultClientStateTransitionHook,
63+
SERVICE_CALL_MAX_RETRY_COUNT,
64+
STATUS_TAG_CLIENT_CALL_FAILED
65+
},
66+
{
67+
CLIENT_STATE_READY,
68+
CLIENT_STATE_GET_TOKEN | CLIENT_STATE_AUTH | CLIENT_STATE_TAG_CLIENT | CLIENT_STATE_CREATE | CLIENT_STATE_READY,
69+
fromReadyClientState,
70+
executeReadyClientState,
71+
defaultClientStateTransitionHook,
72+
INFINITE_RETRY_COUNT_SENTINEL,
73+
STATUS_CLIENT_READY_CALLBACK_FAILED
74+
}
2675
};
2776

2877
UINT32 CLIENT_STATE_MACHINE_STATE_COUNT = SIZEOF(CLIENT_STATE_MACHINE_STATES) / SIZEOF(StateMachineState);
2978

79+
STATUS defaultClientStateTransitionHook(
80+
UINT64 customData /* customData should be PKinesisVideoClient */,
81+
PUINT64 stateTransitionWaitTime) {
82+
ENTERS();
83+
STATUS retStatus = STATUS_SUCCESS;
84+
PKinesisVideoClient pKinesisVideoClient = NULL;
85+
PKvsRetryStrategy pKvsRetryStrategy = NULL;
86+
UINT64 retryWaitTime = 0;
87+
88+
pKinesisVideoClient = CLIENT_FROM_CUSTOM_DATA(customData);
89+
CHK(pKinesisVideoClient != NULL && stateTransitionWaitTime != NULL, STATUS_NULL_ARG);
90+
91+
pKvsRetryStrategy = &(pKinesisVideoClient->deviceInfo.clientInfo.kvsRetryStrategy);
92+
93+
// result > SERVICE_CALL_RESULT_OK covers case for -
94+
// result != SERVICE_CALL_RESULT_NOT_SET and != SERVICE_CALL_RESULT_OK
95+
// If we support any other 2xx service call results, the condition
96+
// should change to (pKinesisVideoStream->base.result > 299 && ...)
97+
CHK(pKinesisVideoClient->base.result > SERVICE_CALL_RESULT_OK &&
98+
pKvsRetryStrategy != NULL &&
99+
pKvsRetryStrategy->pRetryStrategy != NULL &&
100+
pKvsRetryStrategy->executeRetryStrategyFn != NULL, STATUS_SUCCESS);
101+
102+
DLOGD("KinesisVideoClient base result is [%u]. Executing KVS retry handler of retry strategy type [%u]",
103+
pKinesisVideoClient->base.result, pKvsRetryStrategy->retryStrategyType);
104+
pKvsRetryStrategy->executeRetryStrategyFn(pKvsRetryStrategy->pRetryStrategy, &retryWaitTime);
105+
*stateTransitionWaitTime = retryWaitTime;
106+
107+
CleanUp:
108+
109+
LEAVES();
110+
return retStatus;
111+
}
112+
30113
// Helper method for stepping the client state machine
31114
STATUS stepClientStateMachine(PKinesisVideoClient pKinesisVideoClient)
32115
{

src/client/src/Include_i.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,8 +463,13 @@ STATUS executeCreateClientState(UINT64, UINT64);
463463
STATUS executeTagClientState(UINT64, UINT64);
464464
STATUS executeReadyClientState(UINT64, UINT64);
465465

466+
STATUS defaultClientStateTransitionHook(UINT64, PUINT64);
467+
466468
STATUS checkIntermittentProducerCallback(UINT32, UINT64, UINT64);
467469

470+
STATUS freeClientRetryStrategy(PKinesisVideoClient);
471+
STATUS configureClientWithRetryStrategy(PKinesisVideoClient);
472+
468473
#ifdef __cplusplus
469474
}
470475
#endif

src/client/src/Stream.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,8 @@ STATUS executeStreamingStreamState(UINT64, UINT64);
858858
STATUS executeStoppedStreamState(UINT64, UINT64);
859859
STATUS executeTagStreamState(UINT64, UINT64);
860860

861+
STATUS defaultStreamStateTransitionHook(UINT64, PUINT64);
862+
861863
#ifdef __cplusplus
862864
}
863865
#endif

0 commit comments

Comments
 (0)