Skip to content

Commit 1fb276c

Browse files
committed
[PHP Process Manager] Support acquiring a non-primary PHP instance
/** * Get a PHP instance. * * It could be either the primary PHP instance, an idle disposable PHP * instance, or a newly spawned PHP instance – depending on the resource * availability. * * @PARAM considerPrimary - Whether to consider the primary PHP instance. * It matters because PHP.cli() sets the SAPI to CLI and * kills the entire process after it finishes running, * making the primary PHP instance non-reusable for * subsequent .run() calls. This is fine for one-off * child PHP instances, but not for the primary PHP * that's meant to continue working for the entire duration * of the ProcessManager lifetime. Therefore, we don't * consider the primary PHP instance by default unless * the caller explicitly requests it. * * @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached * and the waiting timeout is exceeded. */
1 parent c006fc5 commit 1fb276c

2 files changed

Lines changed: 41 additions & 6 deletions

File tree

‎packages/php-wasm/universal/src/lib/php-process-manager.ts‎

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export class MaxPhpInstancesError extends Error {
7373
*/
7474
export class PHPProcessManager implements AsyncDisposable {
7575
private primaryPhp?: PHP;
76+
private primaryPhpPromise?: Promise<SpawnedPHP>;
7677
private primaryIdle = true;
7778
private nextInstance: Promise<SpawnedPHP> | null = null;
7879
/**
@@ -112,8 +113,11 @@ export class PHPProcessManager implements AsyncDisposable {
112113
'phpFactory or primaryPhp must be set before calling getPrimaryPhp().'
113114
);
114115
} else if (!this.primaryPhp) {
115-
const spawned = await this.spawn!({ isPrimary: true });
116-
this.primaryPhp = spawned.php;
116+
if (!this.primaryPhpPromise) {
117+
this.primaryPhpPromise = this.spawn({ isPrimary: true });
118+
}
119+
this.primaryPhp = (await this.primaryPhpPromise).php;
120+
this.primaryPhpPromise = undefined;
117121
}
118122
return this.primaryPhp!;
119123
}
@@ -125,15 +129,44 @@ export class PHPProcessManager implements AsyncDisposable {
125129
* instance, or a newly spawned PHP instance – depending on the resource
126130
* availability.
127131
*
132+
* @param considerPrimary - Whether to consider the primary PHP instance.
133+
* It matters because PHP.cli() sets the SAPI to CLI and
134+
* kills the entire process after it finishes running,
135+
* making the primary PHP instance non-reusable for
136+
* subsequent .run() calls. This is fine for one-off
137+
* child PHP instances, but not for the primary PHP
138+
* that's meant to continue working for the entire duration
139+
* of the ProcessManager lifetime. Therefore, we don't
140+
* consider the primary PHP instance by default unless
141+
* the caller explicitly requests it.
142+
*
128143
* @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
129144
* and the waiting timeout is exceeded.
130145
*/
131-
async acquirePHPInstance(): Promise<SpawnedPHP> {
132-
if (this.primaryIdle) {
146+
async acquirePHPInstance({
147+
considerPrimary = false,
148+
}: {
149+
considerPrimary?: boolean;
150+
} = {}): Promise<SpawnedPHP> {
151+
/**
152+
* First and foremost, make sure we have the primary PHP instance in place.
153+
* We may not actually acquire it. We just need it to exist.
154+
*
155+
* @TODO: Re-evaluate why we need it to exist. Should spawn() be just more
156+
* lenient with its "another primary instance already started spawning"
157+
* check?
158+
*/
159+
if (!this.primaryPhp) {
160+
await this.getPrimaryPhp();
161+
}
162+
163+
if (this.primaryIdle && considerPrimary) {
133164
this.primaryIdle = false;
134165
return {
135166
php: await this.getPrimaryPhp(),
136-
reap: () => (this.primaryIdle = true),
167+
reap: () => {
168+
this.primaryIdle = true;
169+
},
137170
};
138171
}
139172

‎packages/php-wasm/universal/src/lib/php-request-handler.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,9 @@ export class PHPRequestHandler {
493493
): Promise<PHPResponse> {
494494
let spawnedPHP: SpawnedPHP | undefined = undefined;
495495
try {
496-
spawnedPHP = await this.processManager!.acquirePHPInstance();
496+
spawnedPHP = await this.processManager!.acquirePHPInstance({
497+
considerPrimary: true,
498+
});
497499
} catch (e) {
498500
if (e instanceof MaxPhpInstancesError) {
499501
return PHPResponse.forHttpCode(502);

0 commit comments

Comments
 (0)