77use Doctrine \DBAL \Driver \Statement ;
88use Doctrine \DBAL \ParameterType ;
99use Keboola \TableBackendUtils \Connection \Exception \DriverException ;
10+ use Retry \BackOff \ExponentialBackOffPolicy ;
11+ use Retry \BackOff \ExponentialRandomBackOffPolicy ;
12+ use Retry \BackOff \UniformRandomBackOffPolicy ;
13+ use Retry \Policy \CallableRetryPolicy ;
14+ use Retry \Policy \SimpleRetryPolicy ;
15+ use Retry \RetryProxy ;
1016use Throwable ;
1117
1218class SnowflakeStatement implements Statement
@@ -16,6 +22,8 @@ class SnowflakeStatement implements Statement
1622 */
1723 private $ dbh ;
1824
25+ private RetryProxy $ retry ;
26+
1927 /**
2028 * @var resource
2129 */
@@ -31,8 +39,30 @@ class SnowflakeStatement implements Statement
3139 /**
3240 * @param resource $dbh database handle
3341 */
34- public function __construct ($ dbh , string $ query )
42+ public function __construct ($ dbh , string $ query, RetryProxy | null $ retry = null )
3543 {
44+ if ($ retry === null ) {
45+ $ this ->retry = new RetryProxy (
46+ new CallableRetryPolicy (
47+ function (Throwable $ e ): bool {
48+ if (str_contains ($ e ->getMessage (), 'SYSTEM$ALLOWLIST ' )) {
49+ // Retry in case of SYSTEM$ALLOWLIST error #prod_24_7___inc_25140
50+ // this is usually accompanied with SNFLK incidents
51+ // or can happen in case hostname is wrong
52+ return true ;
53+ }
54+ return false ;
55+ },
56+ 5 , // 5 attempts
57+ ),
58+ new UniformRandomBackOffPolicy (
59+ 3_000 , // 3 seconds
60+ 10_000 , // 10 seconds
61+ ),
62+ );
63+ } else {
64+ $ this ->retry = $ retry ;
65+ }
3666 $ this ->dbh = $ dbh ;
3767 $ this ->query = $ query ;
3868 $ this ->stmt = $ this ->prepare ();
@@ -43,7 +73,10 @@ public function __construct($dbh, string $query)
4373 */
4474 private function prepare ()
4575 {
46- $ stmt = @odbc_prepare ($ this ->dbh , $ this ->query );
76+ /** @var resource|false $stmt */
77+ $ stmt = $ this ->retry ->call (function () {
78+ return @odbc_prepare ($ this ->dbh , $ this ->query );
79+ });
4780 if (!$ stmt ) {
4881 throw DriverException::newFromHandle ($ this ->dbh );
4982 }
@@ -82,8 +115,13 @@ public function execute($params = null): Result
82115 }
83116
84117 try {
85- odbc_execute ($ this ->stmt , $ this ->repairBinding ($ this ->params ));
86- } catch (Throwable $ e ) {
118+ $ this ->retry ->call (function () {
119+ odbc_execute (
120+ $ this ->stmt ,
121+ $ this ->repairBinding ($ this ->params ),
122+ );
123+ });
124+ } catch (Throwable ) {
87125 throw DriverException::newFromHandle ($ this ->dbh );
88126 }
89127
0 commit comments