Dependency Management Guide β
Resource ordering and dependency graphs in Lynq.
Overview β
Lynq uses a DAG (Directed Acyclic Graph) to order resource creation and ensure dependencies are satisfied before applying resources.
Dependency Visualizer β
The Lynq includes an interactive dependency graph visualizer tool that helps you:
- Visualize Dependencies: See the complete dependency graph of your LynqForm
- Detect Cycles: Automatically identify circular dependencies that would cause failures
- Understand Execution Order: View numbered badges showing the order resources will be applied
- Test Your Templates: Paste your YAML and analyze dependencies before deployment
Interactive Tool Available
Visit the π Dependency Visualizer page to analyze your LynqForm dependencies interactively. Load preset examples or paste your own YAML to visualize the dependency graph in real-time.
Defining Dependencies β
Use the dependIds field to specify dependencies:
Syntax
Set dependIds to an array of resource IDs. The controller ensures all referenced resources finish reconciling before applying the dependent resource.
deployments:
- id: app
dependIds: ["secret"] # Wait for secret first
nameTemplate: "{{ .uid }}-app"
spec:
# ... deployment specDependency Resolution β
Topological Sort β
Resources are applied in dependency order:
secret (no dependencies)
β
app (depends on: secret)
β
svc (depends on: app)Cycle Detection β
Circular dependencies are rejected:
Why it fails
Dependency resolution uses a DAG. Any cycle blocks reconciliation and surfaces as DependencyError.
# β This will fail
- id: a
dependIds: ["b"]
- id: b
dependIds: ["a"]Error: DependencyError: Dependency cycle detected: a -> b -> a
Common Patterns β
Pattern 1: Secrets Before Apps β
secrets:
- id: api-secret
nameTemplate: "{{ .uid }}-secret"
# No dependencies
deployments:
- id: app
dependIds: ["api-secret"] # Wait for secretPattern 2: ConfigMap Before Deployment β
configMaps:
- id: app-config
nameTemplate: "{{ .uid }}-config"
deployments:
- id: app
dependIds: ["app-config"] # Wait for configmapPattern 3: App Before Service β
deployments:
- id: app
# No dependencies
services:
- id: svc
dependIds: ["app"] # Wait for deployment firstPattern 4: PVC Before StatefulSet β
persistentVolumeClaims:
- id: data-pvc
# No dependencies
statefulSets:
- id: stateful-app
dependIds: ["data-pvc"] # Wait for PVCDependency Failure Behavior β
skipOnDependencyFailure (Default: true) β
Controls whether a resource should be skipped when any of its dependencies fail (apply error, timeout).
New in v1.1.14
The skipOnDependencyFailure flag provides fine-grained control over dependency failure handling.
deployments:
- id: app
dependIds: ["db"]
skipOnDependencyFailure: true # Default: skip if db failsBehavior:
true(default): Resource is skipped if any dependency fails (apply error or timeout)false: Resource is still created even if dependencies fail
Understanding Blocking vs Failed Dependencies β
Important Distinction (v1.1.14+)
Lynq distinguishes between dependencies that are not ready yet (still progressing) and those that have failed (encountered an error).
| Dependency State | Dependent Resource | DependencySkipped Event | skippedCount |
|---|---|---|---|
| Failed (apply error) | Skipped or created (based on skipOnDependencyFailure) | β Yes (if skipped) | +1 (if skipped) |
Timed out (exceeds timeoutSeconds) | Skipped or created (based on skipOnDependencyFailure) | β Yes (if skipped) | +1 (if skipped) |
| Not ready yet (within timeout) | Blocked (waits for next reconcile) | β No | 0 |
Why this matters:
When a Deployment is starting up (pulling images, scheduling pods), it's "not ready yet" but not failed. Dependent resources:
- Are blocked from creation until the Deployment becomes ready
- Do NOT receive a
DependencySkippedevent (which would be misleading) - Are NOT counted in
skippedResourcesstatus
This prevents confusing alerts like "DependencySkipped: app skipped because db failed" when db is simply still starting up.
Example timeline:
T=0s: Deployment created, status: Progressing
ConfigMap blocked (dependency not ready yet)
NO DependencySkipped event
T=30s: Reconcile runs, Deployment still Progressing
ConfigMap still blocked
NO DependencySkipped event
T=45s: Deployment becomes Ready
Reconcile runs, ConfigMap created
SUCCESS - no skip events emittedCompare this to a failed dependency:
T=0s: Deployment created with invalid image
T=20s: Deployment fails (ImagePullBackOff, timeout exceeded)
DependencySkipped event emitted for ConfigMap
skippedResources: 1When to Skip (Default Behavior) β
The default skipOnDependencyFailure: true is recommended for most resources:
secrets:
- id: db-creds
# ... credentials for database
deployments:
- id: db
dependIds: ["db-creds"]
waitForReady: true
# skipOnDependencyFailure: true (default)
- id: app
dependIds: ["db"]
# skipOnDependencyFailure: true (default)
# App will be SKIPPED if db fails or is not readyUse when:
- Resource would fail anyway without its dependency
- You want to prevent cascading failures
- Resource cannot function without its dependency
When NOT to Skip β
Set skipOnDependencyFailure: false for resources that should be created regardless of dependency status:
deployments:
- id: main-app
dependIds: ["config"]
waitForReady: true
- id: cleanup-job
dependIds: ["main-app"]
skipOnDependencyFailure: false # Create even if main-app fails
spec:
apiVersion: batch/v1
kind: Job
spec:
template:
spec:
containers:
- name: cleanup
image: busybox
command: ["sh", "-c", "echo 'Performing cleanup...'"]
restartPolicy: OnFailureUse when:
- Cleanup or fallback resources that must always run
- Monitoring/alerting resources
- Resources that can partially function without dependency
- Debug or diagnostic resources
Status Tracking β
When resources are skipped, the LynqNode status tracks them:
status:
desiredResources: 5
readyResources: 2
failedResources: 1
skippedResources: 2 # Resources skipped due to dependency failures
skippedResourceIds: # Which specific resources were skipped
- "app"
- "svc"Events emitted:
DependencySkipped: When a resource is skipped due to dependency failureDependencyFailedButProceeding: WhenskipOnDependencyFailure: falseand resource is created despite failure
Examples β
Example 1: Database β App β Service Chain
deployments:
- id: db
waitForReady: true
- id: app
dependIds: ["db"]
# If db fails, app is skipped (default behavior)
services:
- id: svc
dependIds: ["app"]
# If app is skipped, svc is also skippedExample 2: Cleanup Job Always Runs
deployments:
- id: main-app
waitForReady: true
jobs:
- id: cleanup-job
dependIds: ["main-app"]
skipOnDependencyFailure: false # Always create
creationPolicy: OnceExample 3: Monitoring Independent of App
deployments:
- id: app
dependIds: ["config"]
- id: metrics-exporter
dependIds: ["app"]
skipOnDependencyFailure: false # Monitor even if app failsReadiness Gates β
Use waitForReady to wait for resource readiness:
waitForReady: true ensures resource is ready before dependent workloads start Combine readiness and dependencies
dependIds only guarantees creation order. Enable waitForReady to ensure ready status before dependent workloads roll out.
deployments:
- id: db
waitForReady: true
timeoutSeconds: 300
deployments:
- id: app
dependIds: ["db"] # Wait for db to exist AND be ready
waitForReady: trueBest Practices β
1. Shallow Dependencies β
Prefer shallow dependency trees:
Good (depth: 2):
secret
ββ app
β ββ svc
ββ db
ββ db-svcBad (depth: 5):
secret β config β pvc β db β db-svc β app2. Parallel Execution β
Independent resources execute in parallel:
app-a and app-b execute in parallel after secret is ready deployments:
- id: app-a
dependIds: ["secret"] # Both execute in parallel
- id: app-b
dependIds: ["secret"] # Both execute in parallel3. Minimal Dependencies β
Only specify necessary dependencies:
Good:
- id: app
dependIds: ["secret"] # Only essential dependencyBad:
- id: app
dependIds: ["secret", "unrelated-resource"] # Unnecessary waitDebugging Dependencies β
Common Errors β
Cycle detected
DependencyError: Dependency cycle detected: a -> b -> c -> aFix: Remove or refactor at least one edge so the graph becomes acyclic.
Missing dependency
DependencyError: Resource 'app' depends on 'missing-id' which does not existFix: Ensure every dependIds entry references a defined resource ID.
Readiness timeout
ReadinessTimeout: Resource db not ready within 300sFix: Increase timeoutSeconds or set waitForReady: false when readiness should not block dependent resources.
Dependency skipped (expected behavior)
DependencySkipped: Resource 'app' skipped because dependency 'db' failed.Note: This event is emitted only when a dependency actually fails (apply error or timeout), not when it's simply not ready yet. This is expected when skipOnDependencyFailure: true (default). Set to false if the resource should be created anyway.
Dependency blocked (silent waiting)
If your dependent resource isn't being created but there's no DependencySkipped event, the dependency is likely still starting up. Lynq silently blocks dependent resources until dependencies become ready. Check:
# Check if dependency is still progressing
kubectl get deployment <dep-name> -o jsonpath='{.status.conditions}'The dependent resource will be created on the next reconcile after the dependency becomes ready.
Dependency failed but proceeding
DependencyFailedButProceeding: Creating resource 'cleanup' despite dependency 'app' failure (skipOnDependencyFailure: false)Note: Resource is being created as configured. Ensure it can handle missing dependency.
See Also β
- π Dependency Visualizer - Interactive tool for analyzing dependencies
- Template Guide
- Policies Guide
- Troubleshooting Guide
