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

feat: add stop function to allow shutting down the debug agent #1147

Merged
merged 6 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
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