Skip to content

Commit

Permalink
fix: handle all promises and add no-floating-promises linting rule
Browse files Browse the repository at this point in the history
This addresses a few bugs, including error handling issues in the
TaskGraph.
  • Loading branch information
edvald committed Sep 25, 2018
1 parent ec403ee commit f0b4104
Show file tree
Hide file tree
Showing 11 changed files with 40 additions and 122 deletions.
11 changes: 11 additions & 0 deletions garden-cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions garden-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"node-emoji": "^1.8.1",
"node-pty": "^0.7.6",
"normalize-url": "^3.2.0",
"p-queue": "^3.0.0",
"path-is-inside": "^1.0.2",
"shx": "^0.3.2",
"snyk": "^1.90.2",
Expand Down Expand Up @@ -100,6 +101,7 @@
"@types/node": "^10.7.0",
"@types/node-emoji": "^1.8.0",
"@types/normalize-url": "^1.9.1",
"@types/p-queue": "^2.3.1",
"@types/path-is-inside": "^1.0.0",
"@types/prettyjson": "0.0.28",
"@types/string-width": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion garden-cli/src/commands/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class LogsCommand extends Command<Args, Opts> {
const stream = new Stream<ServiceLogEntry>()

// TODO: use basic logger (no need for fancy stuff here, just causes flickering)
stream.forEach((entry) => {
void stream.forEach((entry) => {
// TODO: color each service differently for easier visual parsing
let timestamp = " "

Expand Down
7 changes: 2 additions & 5 deletions garden-cli/src/logger/writers/fancy-terminal-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
import { LogEntry } from "../log-entry"
import { Logger } from "../logger"
import { LogLevel } from "../log-node"
import { sleep } from "../../util/util"
import { getChildEntries, getTerminalWidth, interceptStream, validate } from "../util"
import { Writer, WriterConfig } from "./base"

Expand Down Expand Up @@ -149,13 +148,11 @@ export class FancyTerminalWriter extends Writer {
this.updatePending = true

// Resume processing if idle and original update is still pending
const maybeResume = async () => {
await sleep(FANCY_LOGGER_THROTTLE_MS)
setTimeout(() => {
if (this.updatePending) {
this.handleGraphChange(logEntry, logger, true)
}
}
maybeResume()
}, FANCY_LOGGER_THROTTLE_MS)
return
}
}
Expand Down
2 changes: 1 addition & 1 deletion garden-cli/src/plugins/kubernetes/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ export async function getServiceLogs(
try {
timestamp = moment(timestampStr).toDate()
} catch { }
stream.write({ serviceName: service.name, timestamp, msg })
void stream.write({ serviceName: service.name, timestamp, msg })
})

proc.stderr.pipe(process.stderr)
Expand Down
2 changes: 1 addition & 1 deletion garden-cli/src/plugins/kubernetes/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ async function build({ ctx, module, logEntry }: BuildModuleParams<HelmModule>):
.map(([k, v]) => set(values, k, v))

const valuesPath = getValuesPath(chartPath)
dumpYaml(valuesPath, values)
await dumpYaml(valuesPath, values)

// keep track of which version has been built
const buildVersionFilePath = join(buildPath, GARDEN_BUILD_VERSION_FILENAME)
Expand Down
4 changes: 1 addition & 3 deletions garden-cli/src/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,7 @@ export async function processModules(
if (changedModule) {
garden.log.debug({ msg: `Files changed for module ${changedModule.name}` })

await Bluebird.map(changeHandler!(changedModule), task => {
garden.addTask(task)
})
await Bluebird.map(changeHandler!(changedModule), (task) => garden.addTask(task))
}

await garden.processTasks()
Expand Down
117 changes: 19 additions & 98 deletions garden-cli/src/task-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import * as Bluebird from "bluebird"
import * as PQueue from "p-queue"
import chalk from "chalk"
import { merge, padEnd, pick } from "lodash"
import { Task, TaskDefinitionError } from "./tasks/base"
Expand All @@ -33,21 +34,8 @@ export interface TaskResults {
[baseKey: string]: TaskResult
}

interface LogEntryMap { [key: string]: LogEntry }

export const DEFAULT_CONCURRENCY = 4

const taskStyle = chalk.cyan.bold

function inProgressToStr(nodes) {
return `Currently in progress [${nodes.map(n => taskStyle(n.getKey())).join(", ")}]`
}

function remainingTasksToStr(num) {
const style = num === 0 ? chalk.green : chalk.yellow
return `Remaining tasks ${style.bold(String(num))}`
}

export class TaskGraph {
private roots: TaskNodeMap
private index: TaskNodeMap
Expand All @@ -56,22 +44,26 @@ export class TaskGraph {
private logEntryMap: LogEntryMap

private resultCache: ResultCache
private opQueue: OperationQueue
private opQueue: PQueue

constructor(private garden: Garden, private concurrency: number = DEFAULT_CONCURRENCY) {
this.roots = new TaskNodeMap()
this.index = new TaskNodeMap()
this.inProgress = new TaskNodeMap()
this.resultCache = new ResultCache()
this.opQueue = new OperationQueue(this)
this.opQueue = new PQueue({ concurrency: 1 })
this.logEntryMap = {}
}

addTask(task: Task): Promise<any> {
return this.opQueue.request({ type: "addTask", task })
async addTask(task: Task): Promise<void> {
return this.opQueue.add(() => this.addTaskInternal(task))
}

async addTaskInternal(task: Task) {
async processTasks(): Promise<TaskResults> {
return this.opQueue.add(() => this.processTasksInternal())
}

private async addTaskInternal(task: Task) {
const predecessor = this.getPredecessor(task)
let node = this.getNode(task)

Expand Down Expand Up @@ -109,16 +101,10 @@ export class TaskGraph {
const existing = this.index.getNode(task)
return existing || new TaskNode(task)
}

processTasks(): Promise<TaskResults> {
return this.opQueue.request({ type: "processTasks" })
}

/*
Process the graph until it's complete
*/
async processTasksInternal(): Promise<TaskResults> {

private async processTasksInternal(): Promise<TaskResults> {
const _this = this
const results: TaskResults = {}

Expand Down Expand Up @@ -480,80 +466,15 @@ class ResultCache {

}

// TODO: Add more typing to this class.

/*
Used by TaskGraph to prevent race conditions e.g. when calling addTask or
processTasks.
*/
class OperationQueue {
queue: object[]
draining: boolean

constructor(private taskGraph: TaskGraph) {
this.queue = []
this.draining = false
}

request(opRequest): Promise<any> {
let findFn

switch (opRequest.type) {

case "addTask":
findFn = (o) => o.type === "addTask" && o.task.getBaseKey() === opRequest.task.getBaseKey()
break

case "processTasks":
findFn = (o) => o.type === "processTasks"
break
}

const existingOp = this.queue.find(findFn)

const prom = new Promise((resolver) => {
if (existingOp) {
existingOp["resolvers"].push(resolver)
} else {
this.queue.push({ ...opRequest, resolvers: [resolver] })
}
})

if (!this.draining) {
this.process()
}

return prom
}

async process() {
this.draining = true
const op = this.queue.shift()

if (!op) {
this.draining = false
return
}

switch (op["type"]) {

case "addTask":
const task = op["task"]
await this.taskGraph.addTaskInternal(task)
for (const resolver of op["resolvers"]) {
resolver()
}
break
interface LogEntryMap { [key: string]: LogEntry }

case "processTasks":
const results = await this.taskGraph.processTasksInternal()
for (const resolver of op["resolvers"]) {
resolver(results)
}
break
}
const taskStyle = chalk.cyan.bold

this.process()
}
function inProgressToStr(nodes) {
return `Currently in progress [${nodes.map(n => taskStyle(n.getKey())).join(", ")}]`
}

function remainingTasksToStr(num) {
const style = num === 0 ? chalk.green : chalk.yellow
return `Remaining tasks ${style.bold(String(num))}`
}
12 changes: 0 additions & 12 deletions garden-cli/src/vcs/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import execa = require("execa")
import { join } from "path"
import { ensureDir, pathExists, stat } from "fs-extra"
import { argv } from "process"
import Bluebird = require("bluebird")

import { NEW_MODULE_VERSION, VcsHandler, RemoteSourceParams } from "./base"
Expand Down Expand Up @@ -140,14 +139,3 @@ export class GitHandler extends VcsHandler {
}

}

// used by the build process to resolve and store the tree version for plugin modules
if (require.main === module) {
const path = argv[2]
const handler = new GitHandler(path)

handler.getTreeVersion(path)
.then((treeVersion) => {
console.log(JSON.stringify(treeVersion, null, 4))
})
}
2 changes: 1 addition & 1 deletion garden-cli/src/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export class FSWatcher {

if (configChanged) {
// The added/removed dir contains one or more garden.yml files
this.invalidateCachedForAll()
await this.invalidateCachedForAll()
return changeHandler(null, true)
}

Expand Down
1 change: 1 addition & 0 deletions tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"no-console": false,
"no-debugger": true,
"no-eval": true,
"no-floating-promises": true,
"no-invalid-template-strings": true,
"no-invalid-this": true,
"no-null-keyword": false,
Expand Down

0 comments on commit f0b4104

Please sign in to comment.