pulumi/sdk/nodejs/runtime/settings.ts
joeduffy 1a64fc4bf3 Keepalive the RPC client until logs finish
This ensures RPC channels stay alive until logs finish.  It also
makes provisions for logs that come in *after* shutdown has begun,
but before it has finished, by observing that the keepalive promise
has changed between the time of initiating the callback and running it.
2017-09-09 14:09:21 -07:00

99 lines
3.5 KiB
TypeScript

// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
import { debuggablePromise } from "./debuggable";
// includeStacks dictates whether we include full stack traces in resource errors or not.
let includeStacks: boolean = true;
export function errorString(err: Error): string {
if (includeStacks && err.stack) {
return err.stack;
}
return err.toString();
}
// configured is set to true once configuration has been set.
let configured: boolean;
// monitor is a live connection to the resource monitor connection.
// IDEA: it would be nice to mirror the Protobuf structures as TypeScript interfaces.
let monitor: Object | undefined;
// engine is an optional live connection to the engine. This can be used for logging, etc.
let engine: Object | undefined;
// dryRun tells us whether we're performing a plan (true) versus a real deployment (false).
export let dryRun: boolean;
// hasMonitor returns true if we are currently connected to a resource monitoring service.
export function hasMonitor(): boolean {
return !!monitor;
}
// isDryRun returns true if we are planning.
export function isDryRun(): boolean {
return dryRun;
}
// getMonitor returns the current resource monitoring service client for RPC communications.
export function getMonitor(): Object | undefined {
if (!configured) {
configured = true;
console.warn("warning: Pulumi Fabric monitor is missing; no resources will be created");
}
return monitor;
}
// getEngine returns the current engine, if any, for RPC communications back to the resource engine.
export function getEngine(): Object | undefined {
return engine;
}
// configure initializes the current resource monitor and engine RPC connections, and whether we are performing a "dry
// run" (plan), versus a real deployment. It may only be called once.
export function configure(m: Object | undefined, e: Object | undefined, dr: boolean): void {
if (configured) {
throw new Error("Cannot configure runtime settings more than once");
}
monitor = m;
engine = e;
dryRun = dr;
configured = true;
}
// disconnect permanently disconnects from the server, closing the connections. It waits for the existing RPC
// queue to drain. If any RPCs come in afterwards, however, they will crash the process.
export function disconnect(): void {
let done: Promise<any> | undefined;
let closeCallback: () => Promise<void> = () => {
if (done !== rpcDone) {
// If the done promise has changed, some activity occurred in between callbacks. Wait again.
done = rpcDone;
return debuggablePromise(done.then(closeCallback));
}
// Otherwise, actually perform the close activities.
if (monitor) {
(<any>monitor).close();
monitor = undefined;
}
if (engine) {
(<any>engine).close();
engine = undefined;
}
return Promise.resolve();
};
closeCallback();
}
// rpcDone resolves when the last known client-side RPC call finishes.
let rpcDone: Promise<any> = Promise.resolve();
// rpcKeepAlive registers a pending call to ensure that we don't prematurely disconnect from the server. It returns
// a function that, when invoked, signals that the RPC has completed.
export function rpcKeepAlive(): () => void {
let done: (() => void) | undefined = undefined;
let donePromise = debuggablePromise(new Promise<void>((resolve) => { done = resolve; }));
rpcDone = rpcDone.then(() => donePromise);
return done!;
}