forked from animatedread/Warrior_EA
49 lines
2.4 KiB
MQL5
49 lines
2.4 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Warrior_EA |
|
||
|
|
//| AnimateDread |
|
||
|
|
//| |
|
||
|
|
//| The exponential-backoff retry SHAPE, shared by every call site |
|
||
|
|
//| that retries one transient-lock-prone operation a fixed number |
|
||
|
|
//| of times with an increasing, capped sleep between attempts. Each |
|
||
|
|
//| operation's own arguments differ (a file copy vs a model load), |
|
||
|
|
//| so the shape is factored out behind a tiny callback interface |
|
||
|
|
//| instead of a raw function pointer - MQL5 has no closures, and |
|
||
|
|
//| a function pointer cannot bind the per-call-site arguments. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#ifndef WARRIOR_RETRY_WITH_BACKOFF_MQH
|
||
|
|
#define WARRIOR_RETRY_WITH_BACKOFF_MQH
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| One retryable attempt. quiet is true on every attempt but the |
|
||
|
|
//| last, so an implementation that logs its own per-attempt reason |
|
||
|
|
//| can stay silent until the failure actually matters. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class IRetryableOp
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual bool TryOnce(bool quiet) = 0;
|
||
|
|
};
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Runs op.TryOnce() up to retryAttempts times, sleeping delayMs |
|
||
|
|
//| (doubled each attempt, capped at delayCapMs) between attempts. |
|
||
|
|
//| Returns the first successful attempt's result, or false if every |
|
||
|
|
//| attempt failed. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool RetryWithBackoff(IRetryableOp *op, const int retryAttempts, const int initialDelayMs, const int delayCapMs)
|
||
|
|
{
|
||
|
|
if(CheckPointer(op) == POINTER_INVALID)
|
||
|
|
return false;
|
||
|
|
int delayMs = initialDelayMs;
|
||
|
|
bool ok = false;
|
||
|
|
for(int attempt = 0; attempt < retryAttempts && !ok; attempt++)
|
||
|
|
{
|
||
|
|
if(attempt > 0)
|
||
|
|
{
|
||
|
|
Sleep(delayMs);
|
||
|
|
delayMs = (int)MathMin(delayMs * 2, delayCapMs);
|
||
|
|
}
|
||
|
|
ok = op.TryOnce(attempt < retryAttempts - 1);
|
||
|
|
}
|
||
|
|
return ok;
|
||
|
|
}
|
||
|
|
#endif // WARRIOR_RETRY_WITH_BACKOFF_MQH
|
||
|
|
//+------------------------------------------------------------------+
|