2525import com .google .gson .Gson ;
2626import com .google .gson .reflect .TypeToken ;
2727import java .math .BigDecimal ;
28+ import java .time .Duration ;
2829import java .time .LocalDate ;
2930import java .util .Collections ;
3031import java .util .List ;
3132import java .util .Map ;
3233import java .util .UUID ;
33- import java .util .concurrent .TimeUnit ;
34+ import java .util .concurrent .* ;
3435import lombok .Value ;
3536import lombok .extern .slf4j .Slf4j ;
3637import org .apache .avro .Conversions ;
@@ -595,42 +596,8 @@ private void deployFunction(
595596 new Gson ().fromJson (userConfig , new TypeToken <Map <String , Object >>() {}.getType ()))
596597 .build ();
597598
598- for (int i = 0 ; i < 600 ; i ++) {
599- try {
600- admin .functions ().createFunction (functionConfig , null );
601- break ;
602- } catch (PulsarAdminException e ) {
603- if (e .getMessage () != null && e .getMessage ().contains ("Leader not yet ready" )) {
604- log .info ("Function worker leader not ready yet, retrying... ({}/600)" , i + 1 );
605- Thread .sleep (500 );
606- } else {
607- throw e ;
608- }
609- }
610- }
611-
612- FunctionStatus functionStatus = null ;
613- for (int i = 0 ; i < 600 ; i ++) {
614- functionStatus = admin .functions ().getFunctionStatus ("public" , "default" , functionName );
615- if (functionStatus .getNumRunning () == 1 ) {
616- break ;
617- }
618- log .info ("Function status: {}" , functionStatus );
619- functionStatus
620- .getInstances ()
621- .forEach (
622- f -> {
623- log .info ("Function instance status: {}" , f );
624- if (!StringUtils .isEmpty (f .getStatus ().getError ())) {
625- log .error ("Function errored out " + f );
626- }
627- });
628- Thread .sleep (500 );
629- }
630-
631- if (functionStatus .getNumRunning () != 1 ) {
632- fail ("Function didn't start in time" );
633- }
599+ admin .functions ().createFunction (functionConfig , null );
600+ waitForFunctionRunning (functionName );
634601 }
635602
636603 @ Value
@@ -644,4 +611,53 @@ private static class Pojo2 {
644611 String c ;
645612 String d ;
646613 }
614+
615+ private void waitForFunctionRunning (String functionName ) throws InterruptedException {
616+ ScheduledExecutorService scheduler = Executors .newSingleThreadScheduledExecutor ();
617+ CompletableFuture <Void > future = new CompletableFuture <>();
618+ long deadline = System .currentTimeMillis () + Duration .ofMinutes (5 ).toMillis ();
619+ scheduler .scheduleWithFixedDelay (
620+ () -> {
621+ try {
622+ FunctionStatus status =
623+ admin .functions ().getFunctionStatus ("public" , "default" , functionName );
624+
625+ status .getInstances ().stream ()
626+ .filter (f -> !StringUtils .isEmpty (f .getStatus ().getError ()))
627+ .findFirst ()
628+ .ifPresent (
629+ f ->
630+ future .completeExceptionally (
631+ new RuntimeException ("Function errored out: " + f )));
632+
633+ if (future .isCompletedExceptionally ()) {
634+ scheduler .shutdown ();
635+ return ;
636+ }
637+ if (status .getNumRunning () == 1 ) {
638+ future .complete (null );
639+ scheduler .shutdown ();
640+ return ;
641+ }
642+ if (System .currentTimeMillis () > deadline ) {
643+ future .completeExceptionally (
644+ new RuntimeException ("Function didn't start in time. Status: " + status ));
645+ scheduler .shutdown ();
646+ return ;
647+ }
648+ log .info ("Function not running yet, status: {}" , status );
649+ } catch (PulsarAdminException e ) {
650+ future .completeExceptionally (e );
651+ scheduler .shutdown ();
652+ }
653+ }, 0 , 2 , TimeUnit .SECONDS );
654+
655+ try {
656+ future .get ();
657+ } catch (ExecutionException e ) {
658+ fail (e .getCause ().getMessage ());
659+ } finally {
660+ scheduler .shutdownNow ();
661+ }
662+ }
647663}
0 commit comments