Dependency Management
frank supports stack dependencies through the depends_on configuration field, allowing you to define execution order for your deployments. This ensures that dependent stacks are deployed only after their dependencies have been successfully deployed.
Configuration
The depends_on field is specified in your manifest configuration files (e.g., app.yaml, api.yaml) and accepts a list of stack names that must be deployed before the current stack.
Basic Syntax
# config/dev/api.yaml
manifest: api-deployment.yaml
app: api
version: 1.0.0
depends_on:
- frank-dev-database
- frank-dev-redis
Stack Name Format
Dependencies are specified using the full stack name, which follows the pattern:
{project_code}-{context}-{app_name}
For example, if your configuration is: - project_code: myapp - context: dev - app: api
The stack name would be: myapp-dev-api
Examples
Simple Dependency Chain
# config/dev/database.yaml
manifest: database-deployment.yaml
app: database
# config/dev/api.yaml
manifest: api-deployment.yaml
app: api
depends_on:
- frank-dev-database
# config/dev/web.yaml
manifest: web-deployment.yaml
app: web
depends_on:
- frank-dev-api
Execution Order: 1. frank-dev-database (no dependencies) 2. frank-dev-api (depends on database) 3. frank-dev-web (depends on api)
Multiple Dependencies
# config/dev/api.yaml
manifest: api-deployment.yaml
app: api
depends_on:
- frank-dev-database
- frank-dev-redis
- frank-dev-messaging
The API stack will wait for all three dependencies to complete before deploying.
Complex Dependency Graph
# config/dev/database.yaml
manifest: database-deployment.yaml
app: database
# config/dev/redis.yaml
manifest: redis-deployment.yaml
app: redis
# config/dev/api.yaml
manifest: api-deployment.yaml
app: api
depends_on:
- frank-dev-database
- frank-dev-redis
# config/dev/web.yaml
manifest: web-deployment.yaml
app: web
depends_on:
- frank-dev-api
# config/dev/worker.yaml
manifest: worker-deployment.yaml
app: worker
depends_on:
- frank-dev-database
- frank-dev-redis
Execution Order: 1. frank-dev-database and frank-dev-redis (parallel, no dependencies) 2. frank-dev-api and frank-dev-worker (parallel, both depend on database and redis) 3. frank-dev-web (depends on api)
Error Handling
Circular Dependencies
frank detects and prevents circular dependencies:
# This will cause an error
# config/dev/app1.yaml
depends_on:
- frank-dev-app2
# config/dev/app2.yaml
depends_on:
- frank-dev-app1
Error: circular dependency detected: frank-dev-app1 -> frank-dev-app2
Missing Dependencies
If a stack depends on a non-existent stack:
# config/dev/api.yaml
depends_on:
- frank-dev-nonexistent
Error: stack 'frank-dev-api' depends on 'frank-dev-nonexistent' which does not exist
Usage
Deploy with Dependencies
# Deploy all stacks in dependency order
frank apply
# Deploy specific environment
frank apply dev
# Deploy specific stack (and its dependencies)
frank apply dev/api
Plan with Dependencies
# Plan all stacks in dependency order
frank plan
# Plan specific environment
frank plan dev
Best Practices
-
Keep Dependencies Simple: Avoid complex dependency graphs that are hard to understand and maintain.
-
Use Descriptive Names: Make stack names clear and consistent to avoid confusion in dependencies.
-
Document Dependencies: Consider adding comments in configuration files explaining why dependencies exist.
-
Test Dependency Changes: When modifying dependencies, test with
frank planfirst to ensure the execution order is correct. -
Avoid Deep Chains: Long dependency chains can slow down deployments and make debugging harder.
Implementation Details
- Dependencies are resolved using topological sorting
- Circular dependency detection uses depth-first search
- Stack execution is sequential when dependencies exist
- Failed deployments stop the execution of dependent stacks
- Dependencies are validated before any deployment begins