@@ -53,20 +53,32 @@ public function apiEncodeState($returnTo, $clientID)
5353 */
5454 public function apiCheckSubscriberExists ($ I , $ emailAddress , $ firstName = false , $ customFields = false )
5555 {
56- // Run request.
57- $ results = $ this ->apiRequest (
58- 'subscribers ' ,
59- 'GET ' ,
60- [
61- 'email_address ' => $ emailAddress ,
62- 'include_total_count ' => true ,
56+ // Wait for the API to update.
57+ $ I ->wait (3 );
6358
64- // Some test email addresses might bounce, so we want to check all subscriber states.
65- 'status ' => 'all ' ,
66- ]
59+ // Retry the API request as sometimes there's a lag before the subscriber is queryable via the API.
60+ $ results = $ this ->retryUntil (
61+ function () use ($ emailAddress ) {
62+ $ results = $ this ->apiRequest (
63+ 'subscribers ' ,
64+ 'GET ' ,
65+ [
66+ 'email_address ' => $ emailAddress ,
67+ 'include_total_count ' => true ,
68+
69+ // Check all subscriber states.
70+ 'status ' => 'all ' ,
71+ ]
72+ );
73+
74+ // Return the results only if a subscriber was found, so
75+ // retryUntil() will keep trying otherwise.
76+ return ( $ results ['pagination ' ]['total_count ' ] > 0 ) ? $ results : false ;
77+ }
6778 );
6879
6980 // Check at least one subscriber was returned and it matches the email address.
81+ $ I ->assertNotFalse ($ results );
7082 $ I ->assertGreaterThan (0 , $ results ['pagination ' ]['total_count ' ]);
7183 $ I ->assertEquals ($ emailAddress , $ results ['subscribers ' ][0 ]['email_address ' ]);
7284
@@ -288,4 +300,39 @@ public function apiRequest($endpoint, $method = 'GET', $params = array())
288300 // Return JSON decoded response.
289301 return json_decode ($ result ->getBody ()->getContents (), true );
290302 }
303+
304+ /**
305+ * Repeatedly invokes the given callback until it returns a truthy value, or
306+ * the maximum number of attempts is reached.
307+ *
308+ * Use this to wrap API checks that can be flaky due to ingestion lag at
309+ * Kit's end (e.g. a subscriber created via a form submission isn't always
310+ * immediately queryable via the `subscribers` endpoint).
311+ *
312+ * @since 1.9.4
313+ *
314+ * @param callable $callback Callback to invoke. Should return the value
315+ * to use, or false/null to indicate the
316+ * check has not yet succeeded.
317+ * @param int $attempts Maximum number of attempts.
318+ * @param int $delay Seconds to wait between attempts.
319+ * @return mixed The truthy value returned by $callback, or
320+ * false if all attempts are exhausted.
321+ */
322+ private function retryUntil (callable $ callback , $ attempts = 4 , $ delay = 3 )
323+ {
324+ for ($ i = 0 ; $ i < $ attempts ; $ i ++) {
325+ $ result = $ callback ();
326+ if ($ result ) {
327+ return $ result ;
328+ }
329+
330+ // Don't sleep after the final attempt.
331+ if ($ i < $ attempts - 1 ) {
332+ sleep ($ delay );
333+ }
334+ }
335+
336+ return false ;
337+ }
291338}
0 commit comments