Skip to content
This repository has been archived by the owner on Apr 3, 2024. It is now read-only.

Commit

Permalink
feat: add stop function to allow shutting down the debug agent (#1147)
Browse files Browse the repository at this point in the history
  • Loading branch information
mctavish committed Jun 5, 2023
1 parent c5bbb4e commit c292200
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 6 deletions.
35 changes: 31 additions & 4 deletions src/agent/debuglet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ export interface FindFilesResult {
export class Debuglet extends EventEmitter {
private debug: Debug;
private v8debug: DebugApi | null;
private started: boolean;
private running: boolean;
private project: string | null;
private controller: Controller | null;
Expand Down Expand Up @@ -241,6 +242,9 @@ export class Debuglet extends EventEmitter {
*/
this.v8debug = null;

/** @private {boolean} */
this.started = false;

/** @private {boolean} */
this.running = false;

Expand Down Expand Up @@ -351,6 +355,7 @@ export class Debuglet extends EventEmitter {
* @private
*/
async start(): Promise<void> {
this.started = true;
const stat = util.promisify(fs.stat);

try {
Expand Down Expand Up @@ -734,6 +739,10 @@ export class Debuglet extends EventEmitter {
}

setTimeout(() => {
if (!this.running) {
this.logger.info('Debuglet is stopped; not registering');
return;
}
assert(that.controller);
if (!that.running) {
onError(new Error('Debuglet not running'));
Expand Down Expand Up @@ -785,6 +794,10 @@ export class Debuglet extends EventEmitter {
}

startListeningForBreakpoints_(): void {
if (!this.running) {
this.logger.info('Debuglet is stopped; not listening for breakpoints');
return;
}
assert(this.controller);
// TODO: Handle the case where this.debuggee is null or not properly registered.
this.controller.subscribeToBreakpoints(
Expand Down Expand Up @@ -1072,16 +1085,30 @@ export class Debuglet extends EventEmitter {
}

/**
* Stops the Debuglet. This is for testing purposes only. Stop should only be
* called on a agent that has started (i.e. emitted the 'started' event).
* Calling this while the agent is initializing may not necessarily stop all
* pending operations.
* Stops the Debuglet.
*
* Stop should only be called on a agent that has started.
*/
stop(): void {
if (this.running) {
this.stopController();
} else {
if (!this.started) {
this.logger.info('Attempt to stop Debuglet before it was started');
return;
}
this.on('started', () => {
this.stopController();
});
}
}

stopController(): void {
assert(this.controller);
assert.ok(this.running, 'stop can only be called on a running agent');
this.logger.debug('Stopping Debuglet');
this.running = false;
this.started = false;
this.controller.stop();
this.emit('stopped');
}
Expand Down
2 changes: 1 addition & 1 deletion src/agent/firebase-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ export class FirebaseController implements Controller {
debuglog(`starting to mark every ${this.markActivePeriodMsec} ms`);
this.markActiveInterval = setInterval(() => {
this.markDebuggeeActive();
}, this.markActivePeriodMsec);
}, this.markActivePeriodMsec).unref();
}

/**
Expand Down
13 changes: 12 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import * as util from 'util';
const debuglog = util.debuglog('cdbg');

// Singleton.
let debuglet: Debuglet;
let debuglet: Debuglet | undefined;

/**
* Start the Debug agent that will make your application available for debugging
Expand Down Expand Up @@ -86,3 +86,14 @@ function mergeConfigs<T>(options: T & {debug?: T}): T {
export function get(): Debuglet | undefined {
return debuglet;
}

/**
* Cleanly shut down the debug agent.
*
* This will free up all resources. It may be necessary to call this to allow
* your process to shut down cleanly.
*/
export function stop(): void {
debuglet?.stop();
debuglet = undefined;
}
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/allowExpressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@

import * as debug from '@google-cloud/debug-agent';
debug.start({allowExpressions: true});
debug.stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/allowExpressionsJs.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
require('@google-cloud/debug-agent').start({
allowExpressions: true,
});
require('@google-cloud/debug-agent').stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/completeServiceContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ debug.start({
version: 'Some version',
},
});
debug.stop();
16 changes: 16 additions & 0 deletions system-test/fixtures/sample/src/firebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2023 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import * as debug from '@google-cloud/debug-agent';
debug.start({useFirebase: true});
debug.stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@

import * as debug from '@google-cloud/debug-agent';
debug.start();
debug.stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/noargs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@

import * as debug from '@google-cloud/debug-agent';
debug.start();
debug.stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/partialCapture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ debug.start({
maxFrames: 1,
},
});
debug.stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/partialServiceContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ debug.start({
service: 'Some service',
},
});
debug.stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
// limitations under the License.

require('@google-cloud/debug-agent').start();
require('@google-cloud/debug-agent').stop();
1 change: 1 addition & 0 deletions system-test/fixtures/sample/src/startEmpty.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
// limitations under the License.

require('@google-cloud/debug-agent').start({});
require('@google-cloud/debug-agent').stop();
43 changes: 43 additions & 0 deletions test/test-debuglet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,49 @@ describe('Debuglet', () => {
debuglet.start();
});

it('should stop successfully even if stop is called quickly', () => {
const debug = new Debug(
{projectId: 'fake-project', credentials: fakeCredentials},
packageInfo
);

nocks.oauth2();

const config = debugletConfig();
const debuglet = new Debuglet(debug, config);

debuglet.start();
debuglet.stop();
});

it('should register successfully even if stop was called first', done => {
const debug = new Debug(
{projectId: 'fake-project', credentials: fakeCredentials},
packageInfo
);

nocks.oauth2();

const config = debugletConfig();
const debuglet = new Debuglet(debug, config);
const scope = nock(config.apiUrl)
.post(REGISTER_PATH)
.reply(200, {
debuggee: {id: DEBUGGEE_ID},
});

debuglet.once('registered', (id: string) => {
assert.strictEqual(id, DEBUGGEE_ID);
debuglet.stop();
scope.done();
done();
});

debuglet.stop();

debuglet.start();
});

it('should attempt to retrieve cluster name if needed', done => {
const savedRunningOnGCP = Debuglet.runningOnGCP;
Debuglet.runningOnGCP = () => {
Expand Down

0 comments on commit c292200

Please sign in to comment.