pulumi/sdk/nodejs/runtime/settings.ts
joeduffy 087deb7643 Add optional dependsOn to Resource constructors
This change adds an optiona dependsOn parameter to Resource constructors,
to "force" a fake dependency between resources.  We have an extremely strong
desire to resort to using this only in unusual cases -- and instead rely
on the natural dependency DAG based on properties -- but experience in other
resource provisioning frameworks tells us that we're likely to need this in
the general case.  Indeed, we've already encountered the need in AWS's
API Gateway resources... and I suspect we'll run into more especially as we
tackle non-serverless resources like EC2 Instances, where "ambient"
dependencies are far more commonplace.

This also makes parallelism the default mode of operation, and we have a
new --serialize flag that can be used to suppress this default behavior.
Full disclosure: I expect this to become more Make-like, i.e. -j 8, where
you can specify the precise width of parallelism, when we tackle
pulumi/pulumi-fabric#106.  I also think there's a good chance we will flip
the default, so that serial execution is the default, so that developers
who don't benefit from the parallelism don't need to worry about dependsOn
in awkward ways.  This tends to be the way most tools (like Make) operate.

This fixes pulumi/pulumi-fabric#335.
2017-09-15 16:38:52 -07:00

87 lines
3.5 KiB
TypeScript

// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
import { debuggablePromise } from "./debuggable";
// Options is a bag of settings that controls the behavior of planning and deployments.
export interface Options {
readonly engine?: Object; // a live connection to the engine, used for logging, etc.
readonly monitor?: Object; // a live connection to the resource monitor that tracks deployments.
readonly serialize?: boolean; // true to serialize resource operations (by default, parallelism is on based on the DAG).
readonly dryRun?: boolean; // whether we are performing a plan (true) or a real deployment (false).
readonly includeStacks?: boolean; // whether we include full stack traces in resource errors or not.
}
// options are the current deployment options being used for this entire session.
export let options: Options = {
serialize: false,
dryRun: false,
includeStacks: true,
};
// configured is set to true once configuration has been set.
let configured: boolean;
// hasMonitor returns true if we are currently connected to a resource monitoring service.
export function hasMonitor(): boolean {
return !!options.monitor;
}
// 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 options.monitor;
}
// getEngine returns the current engine, if any, for RPC communications back to the resource engine.
export function getEngine(): Object | undefined {
return options.engine;
}
// configure initializes the current resource monitor and engine RPC connections, and whether we are performing a "dry
// run" (plan), versus a real deployment, and so on. It may only be called once.
export function configure(opts: Options): void {
if (configured) {
throw new Error("Cannot configure runtime settings more than once");
}
Object.assign(options, opts);
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 (options.monitor) {
(<any>options.monitor).close();
}
if (options.engine) {
(<any>options.engine).close();
}
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!;
}