@@ -7,11 +7,11 @@ import debugFactory from 'debug';
77
88import { decoder } from './codec' ;
99import type { AppManager } from '../../AppManager' ;
10- import type { AppLogStorage } from '../../storage' ;
10+ import type { AppLogStorage , IAppStorageItem } from '../../storage' ;
1111import type { AppBridges } from '../../bridges' ;
1212import type { IParseAppPackageResult } from '../../compiler' ;
13+ import { AppConsole , type ILoggerStorageEntry } from '../../logging' ;
1314import type { AppAccessorManager , AppApiManager } from '../../managers' ;
14- import type { ILoggerStorageEntry } from '../../logging' ;
1515import { AppStatus } from '../../../definition/AppStatus' ;
1616import { bundleLegacyApp } from './bundler' ;
1717import { ProcessMessenger } from './ProcessMessenger' ;
@@ -103,7 +103,7 @@ export class DenoRuntimeSubprocessController extends EventEmitter {
103103 private readonly livenessManager : LivenessManager ;
104104
105105 // We need to keep the appSource around in case the Deno process needs to be restarted
106- constructor ( manager : AppManager , private readonly appPackage : IParseAppPackageResult ) {
106+ constructor ( manager : AppManager , private readonly appPackage : IParseAppPackageResult , private readonly storageItem : IAppStorageItem ) {
107107 super ( ) ;
108108
109109 this . debug = baseDebug . extend ( appPackage . info . id ) ;
@@ -164,23 +164,38 @@ export class DenoRuntimeSubprocessController extends EventEmitter {
164164 }
165165 }
166166
167- public async killProcess ( ) : Promise < void > {
167+ /**
168+ * Attempts to kill the process currently controlled by this.deno
169+ *
170+ * @returns boolean - if a process has been killed or not
171+ */
172+ public async killProcess ( ) : Promise < boolean > {
173+ if ( ! this . deno ) {
174+ this . debug ( 'No child process reference' ) ;
175+ return false ;
176+ }
177+
178+ let { killed } = this . deno ;
179+
168180 // This field is not populated if the process is killed by the OS
169- if ( this . deno . killed ) {
181+ if ( killed ) {
170182 this . debug ( 'App process was already killed' ) ;
171- return ;
183+ return killed ;
172184 }
173185
174186 // What else should we do?
175187 if ( this . deno . kill ( 'SIGKILL' ) ) {
176188 // Let's wait until we get confirmation the process exited
177189 await new Promise < void > ( ( r ) => this . deno . on ( 'exit' , r ) ) ;
190+ killed = true ;
178191 } else {
179192 this . debug ( 'Tried killing the process but failed. Was it already dead?' ) ;
193+ killed = false ;
180194 }
181195
182196 delete this . deno ;
183197 this . messenger . clearReceiver ( ) ;
198+ return killed ;
184199 }
185200
186201 // Debug purposes, could be deleted later
@@ -200,7 +215,7 @@ export class DenoRuntimeSubprocessController extends EventEmitter {
200215
201216 public async getStatus ( ) : Promise < AppStatus > {
202217 // If the process has been terminated, we can't get the status
203- if ( this . deno . exitCode !== null ) {
218+ if ( ! this . deno || this . deno . exitCode !== null ) {
204219 return AppStatus . UNKNOWN ;
205220 }
206221
@@ -231,19 +246,49 @@ export class DenoRuntimeSubprocessController extends EventEmitter {
231246
232247 public async restartApp ( ) {
233248 this . debug ( 'Restarting app subprocess' ) ;
249+ const logger = new AppConsole ( 'runtime:restart' ) ;
250+
251+ logger . info ( 'Starting restart procedure for app subprocess...' , this . livenessManager . getRuntimeData ( ) ) ;
234252
235253 this . state = 'restarting' ;
236254
237- await this . killProcess ( ) ;
255+ try {
256+ const pid = this . deno ?. pid ;
238257
239- await this . setupApp ( ) ;
258+ const hasKilled = await this . killProcess ( ) ;
240259
241- // setupApp() changes the state to 'ready' - we'll need to workaround that for now
242- this . state = 'restarting' ;
260+ if ( hasKilled ) {
261+ logger . debug ( 'Process successfully terminated' , { pid } ) ;
262+ } else {
263+ logger . warn ( 'Could not terminate process. Maybe it was already dead?' , { pid } ) ;
264+ }
243265
244- await this . sendRequest ( { method : 'app:initialize' } ) ;
266+ await this . setupApp ( ) ;
267+ logger . info ( 'New subprocess successfully spawned' , { pid : this . deno . pid } ) ;
245268
246- this . state = 'ready' ;
269+ // setupApp() changes the state to 'ready' - we'll need to workaround that for now
270+ this . state = 'restarting' ;
271+
272+ // When an app has just been installed, the status in the storageItem passed to this controller will be "initialized"
273+ // So, whenever we get that value here, let's just make it 'auto_enabled'
274+ let { status } = this . storageItem ;
275+
276+ if ( status === AppStatus . INITIALIZED ) {
277+ logger . info ( 'Stored status was "initialized". Changing to "auto_enabled"' ) ;
278+ status = AppStatus . AUTO_ENABLED ;
279+ }
280+
281+ await this . sendRequest ( { method : 'app:initialize' } ) ;
282+ await this . sendRequest ( { method : 'app:setStatus' , params : [ status ] } ) ;
283+
284+ this . state = 'ready' ;
285+
286+ logger . info ( 'Successfully restarted app subprocess' ) ;
287+ } catch ( e ) {
288+ logger . error ( "Failed to restart app's subprocess" , { error : e } ) ;
289+ } finally {
290+ await this . logStorage . storeEntries ( AppConsole . toStorageEntry ( this . getAppId ( ) , logger ) ) ;
291+ }
247292 }
248293
249294 public getAppId ( ) : string {
0 commit comments