@@ -36,16 +36,12 @@ public function __construct(
3636 $ this ->command = $ command ?? Command::fromEnv ();
3737 }
3838
39- public static function create (?Command $ command = null ): self
39+ public static function create (?Command $ command = null , ? SystemInfo $ systemInfo = null ): self
4040 {
4141 $ token = \getenv ('GITHUB_TOKEN ' );
4242 $ allowExternalTemporalProcess = \getenv ('ALLOW_EXTERNAL_TEMPORAL_PROCESS ' ) === 'true ' ;
4343
44- $ systemInfo = SystemInfo::detect ();
45- $ roadRunnerBinary = \getenv ('ROADRUNNER_BINARY ' );
46- if (\is_string ($ roadRunnerBinary )) {
47- $ systemInfo ->rrExecutable = $ roadRunnerBinary ;
48- }
44+ $ systemInfo ??= SystemInfo::detect ();
4945
5046 return new self (
5147 new TestOutputStyle (new ArgvInput (), new ConsoleOutput ()),
@@ -60,15 +56,6 @@ public static function create(?Command $command = null): self
6056 );
6157 }
6258
63- /**
64- * @param array<string, mixed> $envs
65- */
66- public function start (?array $ rrCommand = null , int $ commandTimeout = 10 , array $ envs = [], string $ roadRunnerConfigFile = '.rr.yaml ' ): void
67- {
68- $ this ->startTemporalTestServer ($ commandTimeout );
69- $ this ->startRoadRunner ($ rrCommand , $ commandTimeout , $ envs , $ roadRunnerConfigFile );
70- }
71-
7259 /**
7360 * @param list<non-empty-string> $parameters
7461 * @param array<non-empty-string, ValueType|non-empty-string> $searchAttributes Key is the name of the search
@@ -87,7 +74,6 @@ public function startTemporalServer(
8774 $ temporalHost = \parse_url ($ temporalServerAddress , PHP_URL_HOST );
8875 $ temporalPort = \parse_url ($ temporalServerAddress , PHP_URL_PORT );
8976
90- // Add search attributes
9177 foreach ($ searchAttributes as $ name => $ type ) {
9278 $ type = \is_string ($ type ) ? ValueType::tryFrom ($ type ) : $ type ;
9379 if (!$ type instanceof ValueType) {
@@ -112,104 +98,75 @@ public function startTemporalServer(
11298 };
11399 }
114100
115- $ this ->io ->info ('Starting Temporal server... ' );
116- $ this ->temporalServerProcess = new Process (
117- [
118- $ this ->systemInfo ->temporalCliExecutable ,
119- "server " , "start-dev " ,
120- "--port " , $ temporalPort ,
121- '--log-level ' , 'error ' ,
122- '--ip ' , $ temporalHost ,
123- // '--headless',
124- ...$ parameters ,
125- ],
126- );
127- $ this ->temporalServerProcess ->setTimeout ($ commandTimeout );
128- $ temporalStarted = false ;
129- $ this ->io ->info ('Running command: ' . $ this ->serializeProcess ($ this ->temporalServerProcess ));
130- $ this ->temporalServerProcess ->start ();
131-
132- $ deadline = \microtime (true ) + (float ) $ commandTimeout ;
133- while (!$ temporalStarted && \microtime (true ) < $ deadline ) {
134- \usleep (10_000 );
101+ $ process = new Process ([
102+ $ this ->systemInfo ->temporalCliExecutable ,
103+ "server " , "start-dev " ,
104+ "--port " , $ temporalPort ,
105+ '--log-level ' , 'error ' ,
106+ '--ip ' , $ temporalHost ,
107+ ...$ parameters ,
108+ ]);
109+ $ process ->setTimeout ($ commandTimeout );
110+ $ this ->temporalServerProcess = $ process ;
111+
112+ $ this ->runProcess ('Temporal ' , $ process , $ commandTimeout , function () use ($ temporalServerAddress ): bool {
135113 $ check = new Process ([
136114 $ this ->systemInfo ->temporalCliExecutable ,
137115 'operator ' ,
138116 'cluster ' ,
139117 'health ' ,
140118 '--address ' , $ temporalServerAddress ,
141119 ]);
120+ $ check ->setTimeout (1 );
142121 $ check ->run ();
143- if (\str_contains ($ check ->getOutput (), 'SERVING ' )) {
144- $ temporalStarted = true ;
145- }
146- }
147122
148- if (!$ temporalStarted || !$ this ->temporalServerProcess ->isRunning ()) {
149- $ errorOutput = $ this ->temporalServerProcess ->getErrorOutput ();
123+ return \str_contains ($ check ->getOutput (), 'SERVING ' );
124+ }, onFailure: function (Process $ process ): void {
125+ $ errorOutput = $ process ->getErrorOutput ();
126+
150127 if (!$ this ->allowExternalTemporalProcess || !\str_contains ($ errorOutput , 'address already in use ' )) {
151128 $ this ->io ->error ([
152- \sprintf (
153- 'Error starting Temporal server: %s. ' ,
154- !$ temporalStarted ? "Health check failed " : $ errorOutput ,
155- ),
156- \sprintf (
157- 'Command: `%s`. ' ,
158- $ this ->serializeProcess ($ this ->temporalServerProcess ),
159- ),
129+ \sprintf ('Error starting Temporal server: %s. ' , $ errorOutput ?: "Health check failed " ),
130+ \sprintf ('Command: `%s`. ' , $ this ->serializeProcess ($ process )),
160131 ]);
161132 exit (1 );
162133 }
163134 $ this ->io ->warning ('Using external Temporal Server ' );
164-
165135 $ this ->externalTemporalProcessActive = true ;
166- }
167- $ this ->io ->info ('Temporal server started. ' );
136+ });
168137 }
169138
170139 public function startTemporalTestServer (int $ commandTimeout = 10 ): void
171140 {
172- if (!$ this ->downloader ->check ($ this ->systemInfo ->temporalServerExecutable )) {
173- $ this ->io ->info ('Download Temporal test server... ' );
174- $ this ->downloader ->download ($ this ->systemInfo );
175- $ this ->io ->info ('Temporal test server downloaded. ' );
176- }
177-
178141 $ temporalPort = \parse_url ((string ) $ this ->command ->address , PHP_URL_PORT );
179142
180- $ this ->io -> info ( ' Starting Temporal test server... ' );
181- $ this -> temporalTestServerProcess = new Process (
182- [ $ this ->systemInfo -> temporalServerExecutable , $ temporalPort , ' --enable-time-skipping ' ],
183- );
184- $ this ->temporalTestServerProcess -> setTimeout ( $ commandTimeout);
185- $ this -> temporalTestServerProcess -> start ( );
143+ $ process = new Process ([ $ this ->systemInfo -> temporalServerExecutable , $ temporalPort , ' --enable-time-skipping ' ] );
144+ $ process -> setTimeout ( $ commandTimeout );
145+ $ this ->temporalTestServerProcess = $ process ;
146+
147+ $ this ->runProcess ( ' Temporal Test ' , $ process , $ commandTimeout, static function (): bool {
148+ \sleep ( 1 );
186149
187- \sleep (1 );
150+ return true ;
151+ }, onFailure: function (Process $ process ): void {
152+ $ errorOutput = $ process ->getErrorOutput ();
188153
189- if (!$ this ->temporalTestServerProcess ->isRunning ()) {
190- $ errorOutput = $ this ->temporalTestServerProcess ->getErrorOutput ();
191154 if (!$ this ->allowExternalTemporalProcess || !\str_contains ($ errorOutput , 'address already in use ' )) {
192155 $ this ->io ->error ([
193- \sprintf (
194- 'Error starting Temporal Test server: %s. ' ,
195- $ errorOutput ,
196- ),
197- \sprintf (
198- 'Command: `%s`. ' ,
199- $ this ->serializeProcess ($ this ->temporalTestServerProcess ),
200- ),
156+ \sprintf ('Error starting Temporal Test server: %s. ' , $ errorOutput ),
157+ \sprintf ('Command: `%s`. ' , $ this ->serializeProcess ($ process )),
201158 ]);
202159 exit (1 );
203160 }
204161 $ this ->io ->warning ('Using external Temporal Test Server ' );
205- }
206- $ this -> io -> info ( ' Temporal Test server started. ' );
162+ $ this -> externalTemporalProcessActive = true ;
163+ } );
207164 }
208165
209166 /**
210167 * @param array<string, mixed> $envs
211168 */
212- public function startRoadRunner (? array $ rrCommand = null , int $ commandTimeout = 10 , array $ envs = [], string $ configFile = '.rr.yaml ' ): void
169+ public function startRoadRunner (array $ rrCommand , int $ commandTimeout = 10 , array $ envs = [], string $ configFile = '.rr.yaml ' ): void
213170 {
214171 if (!$ this ->isTemporalRunning () && !$ this ->isTemporalTestRunning ()) {
215172 $ this ->io ->error ([
@@ -218,43 +175,21 @@ public function startRoadRunner(?array $rrCommand = null, int $commandTimeout =
218175 exit (1 );
219176 }
220177
221- $ this ->roadRunnerProcess = new Process (
222- command: $ rrCommand ?? [$ this ->systemInfo ->rrExecutable , 'serve ' ],
223- env: $ envs ,
224- );
225- $ this ->roadRunnerProcess ->setTimeout ($ commandTimeout );
178+ $ process = new Process (command: $ rrCommand , env: $ envs , timeout: $ commandTimeout );
179+ $ this ->roadRunnerProcess = $ process ;
226180
227- $ this ->io ->info ('Starting RoadRunner... ' );
228- $ roadRunnerStarted = false ;
229- $ this ->io ->info ('Running command: ' . $ this ->serializeProcess ($ this ->roadRunnerProcess ));
230- $ this ->roadRunnerProcess ->start ();
181+ $ this ->runProcess ('RoadRunner ' , $ process , $ commandTimeout , function () use ($ process , $ configFile ) {
182+ $ output = $ process ->getOutput ();
183+ if (!\str_contains ($ output , 'RoadRunner server started ' )) {
184+ return false ;
185+ }
231186
232- // wait for roadrunner to start
233- $ deadline = \microtime (true ) + (float ) $ commandTimeout ;
234- while (!$ roadRunnerStarted && \microtime (true ) < $ deadline ) {
235- \usleep (10_000 );
236187 $ check = new Process ([$ this ->systemInfo ->rrExecutable , 'workers ' , '-c ' , $ configFile ]);
188+ $ check ->setTimeout (1 );
237189 $ check ->run ();
238- if (\str_contains ($ check ->getOutput (), 'Workers of ' )) {
239- $ roadRunnerStarted = true ;
240- }
241- }
242190
243- if (!$ roadRunnerStarted ) {
244- $ this ->io ->error (\sprintf (
245- 'Failed to start until RoadRunner is ready. Status: "%s". Stderr: "%s". Stdout: "%s". ' ,
246- $ this ->roadRunnerProcess ->getStatus (),
247- $ this ->roadRunnerProcess ->getErrorOutput (),
248- $ this ->roadRunnerProcess ->getOutput (),
249- ));
250- $ this ->io ->writeln (\sprintf (
251- "Command: `%s`. " ,
252- $ this ->serializeProcess ($ this ->roadRunnerProcess ),
253- ));
254- exit (1 );
255- }
256-
257- $ this ->io ->info ('RoadRunner server started. ' );
191+ return \str_contains ($ check ->getOutput (), 'Workers of ' );
192+ });
258193 }
259194
260195 public function stop (): void
@@ -333,6 +268,41 @@ public function isTemporalTestRunning(): bool
333268 $ this ->temporalTestServerProcess ?->isRunning() === true ;
334269 }
335270
271+ private function runProcess (string $ name , Process $ process , int $ commandTimeout , callable $ readiness , ?callable $ onFailure = null ): void
272+ {
273+ $ this ->io ->info (\sprintf ("Starting %s server... " , $ name ));
274+ $ this ->io ->info ('Running command: ' . $ this ->serializeProcess ($ process ));
275+ $ process ->start ();
276+
277+ $ deadline = \microtime (true ) + (float ) $ commandTimeout ;
278+
279+ while ($ process ->isRunning () && \microtime (true ) < $ deadline ) {
280+ if ($ readiness ()) {
281+ break ;
282+ }
283+ \usleep (10_000 );
284+ }
285+
286+ if (!$ process ->isRunning ()) {
287+ ($ onFailure ?? function (Process $ process ) use ($ name ): void {
288+ $ this ->io ->error (\sprintf (
289+ 'Failed to start until %s is ready. Status: "%s". Stderr: "%s". Stdout: "%s". ' ,
290+ $ name ,
291+ $ process ->getStatus (),
292+ $ process ->getErrorOutput (),
293+ $ process ->getOutput (),
294+ ));
295+ $ this ->io ->writeln (\sprintf (
296+ "Command: `%s`. " ,
297+ $ this ->serializeProcess ($ process ),
298+ ));
299+ exit (1 );
300+ })($ process );
301+ }
302+
303+ $ this ->io ->info (\sprintf ("%s server started. " , $ name ));
304+ }
305+
336306 private function stopTemporalTestServerProcess (): void
337307 {
338308 if ($ this ->externalTemporalProcessActive ) {
0 commit comments