Skip to content

Commit

Permalink
fix: performance regression on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
edvald committed Dec 4, 2018
1 parent d46341d commit b856e36
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 26 deletions.
8 changes: 2 additions & 6 deletions garden-service/src/dependency-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,8 @@ export class DependencyGraph {
private testConfigModuleMap: { [key: string]: Module }

static async factory(garden: Garden) {
const { modules, services, tasks } = await Bluebird.props({
modules: garden.getModules(),
services: garden.getServices(),
tasks: garden.getTasks(),
})

const modules = await garden.getModules()
const { services, tasks } = await garden.getServicesAndTasks()
return new DependencyGraph(garden, modules, services, tasks)
}

Expand Down
12 changes: 3 additions & 9 deletions garden-service/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -814,23 +814,17 @@ export class Garden {

this.modulesScanned = true

await this.detectCircularDependencies()

const moduleConfigContext = new ModuleConfigContext(
this, this.log, this.environment, Object.values(this.moduleConfigs),
)
this.moduleConfigs = await resolveTemplateStrings(this.moduleConfigs, moduleConfigContext)

await this.detectCircularDependencies()
})
}

private async detectCircularDependencies() {
const { modules, services, tasks } = await Bluebird.props({
modules: this.getModules(),
services: this.getServices(),
tasks: this.getTasks(),
})

return detectCircularDependencies(modules, services, tasks)
return detectCircularDependencies(Object.values(this.moduleConfigs))
}

/*
Expand Down
21 changes: 12 additions & 9 deletions garden-service/src/util/detectCycles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@

import dedent = require("dedent")
import { get, isEqual, join, set, uniqWith } from "lodash"
import { Module, getModuleKey } from "../types/module"
import {
ConfigurationError,
} from "../exceptions"
import { Service } from "../types/service"
import { Task } from "../types/task"
import { getModuleKey } from "../types/module"
import { ConfigurationError } from "../exceptions"
import { ServiceConfig } from "../config/service"
import { TaskConfig } from "../config/task"
import { ModuleConfig } from "../config/module"

export type Cycle = string[]

Expand All @@ -24,16 +23,18 @@ export type Cycle = string[]
Throws an error if cycles were found.
*/
export async function detectCircularDependencies(modules: Module[], services: Service[], tasks: Task[]) {
export async function detectCircularDependencies(moduleConfigs: ModuleConfig[]) {
// Sparse matrices
const buildGraph = {}
const runtimeGraph = {}
const services: ServiceConfig[] = []
const tasks: TaskConfig[] = []

/*
There's no need to account for test dependencies here, since any circularities there
are accounted for via service dependencies.
*/
for (const module of modules) {
for (const module of moduleConfigs) {
// Build dependencies
for (const buildDep of module.build.dependencies) {
const depName = getModuleKey(buildDep.name, buildDep.plugin)
Expand All @@ -42,12 +43,14 @@ export async function detectCircularDependencies(modules: Module[], services: Se

// Runtime (service & task) dependencies
for (const service of module.serviceConfigs || []) {
services.push(service)
for (const depName of service.dependencies) {
set(runtimeGraph, [service.name, depName], { distance: 1, next: depName })
}
}

for (const task of module.taskConfigs || []) {
tasks.push(task)
for (const depName of task.dependencies) {
set(runtimeGraph, [task.name, depName], { distance: 1, next: depName })
}
Expand All @@ -56,7 +59,7 @@ export async function detectCircularDependencies(modules: Module[], services: Se

const serviceNames = services.map(s => s.name)
const taskNames = tasks.map(w => w.name)
const buildCycles = detectCycles(buildGraph, modules.map(m => m.name))
const buildCycles = detectCycles(buildGraph, moduleConfigs.map(m => m.name))
const runtimeCycles = detectCycles(runtimeGraph, serviceNames.concat(taskNames))

if (buildCycles.length > 0 || runtimeCycles.length > 0) {
Expand Down
7 changes: 5 additions & 2 deletions garden-service/test/src/tasks/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import { BaseTask } from "../../../src/tasks/base"
import { LogEntry } from "../../../src/logger/log-entry"

async function sortedBaseKeysWithDependencies(tasks: BaseTask[]): Promise<string[]> {
return sortedBaseKeys(flatten([tasks].concat(await Bluebird.map(tasks, t => t.getDependencies()))))
const dependencies = await Bluebird.map(tasks, async (t) => t.getDependencies(), { concurrency: 1 })
const tasksWithDependencies = flatten([tasks].concat(dependencies))
return sortedBaseKeys(tasksWithDependencies)
}

function sortedBaseKeys(tasks: BaseTask[]): string[] {
return uniq(tasks.map(t => t.getBaseKey())).sort()
}

describe("TaskHelpers", () => {

let garden: Garden
let log: LogEntry

Expand All @@ -34,6 +35,8 @@ describe("TaskHelpers", () => {

it("returns the correct set of tasks for the changed module", async () => {
const module = await garden.getModule("good-morning")
await garden.getDependencyGraph()

const tasks = await getTasksForModule({
garden, log, module, hotReloadServiceNames: [], force: true, forceBuild: true,
fromWatch: false, includeDependants: false,
Expand Down

0 comments on commit b856e36

Please sign in to comment.