Development Workflow Reference
Understanding stage categories helps compose valid pipelines. Stages must appear in this order:
Overview
Development Workflow Reference
Pipeline Stage Categories
Understanding stage categories helps compose valid pipelines. Stages must appear in this order:
| Category | Stages | Rules |
|---|---|---|
| Source (1, required) | $source | Must be first. One per pipeline. |
| Stateless Processing | $match, $project, $addFields, $unset, $unwind, $replaceRoot, $redact | Can appear anywhere after source. No state or memory overhead. |
| Enrichment | $lookup, $https | I/O-bound. Use parallelism setting. Place $https after windows to batch. |
| Stateful/Window | $tumblingWindow, $hoppingWindow, $sessionWindow | Accumulates state in memory. Monitor memoryUsageBytes. |
| Validation | $validate | Schema enforcement. Use validationAction: "dlq" (not "error"). Place early to catch bad data. |
| Custom Code | $function | JavaScript UDFs. Requires SP30+. |
| Output (1+, required for deployed) | $merge, $emit | Must be last. Required for persistent processors. Sinkless = ephemeral only. |
Key ordering principle: Place $match as early as possible (reduces volume for all downstream stages). Place $project after $match (reduces document size). Place $https after windows (batches API calls).
5-Phase Development Lifecycle
Phase 1: Project Setup
Goal: Workspace and connections ready.
-
Discover existing resources:
atlas-streams-discover→list-workspaces— see what already exists- If workspace exists,
inspect-workspaceto review config
-
Create workspace (if needed):
atlas-streams-build→resource: "workspace"- Choose region close to your data sources
- Start with
tier: "SP10"for development includeSampleData: true(default) gives yousample_stream_solarfor testing
-
Verify workspace:
atlas-streams-discover→inspect-workspace— confirm state and region
Phase 2: Connection Development
Goal: All data sources and sinks connected and verified.
-
Identify required connections:
- Source connections (Kafka, Cluster change streams, Kinesis, Sample)
- Sink connections (Cluster for
$merge, Kafka for$emit, S3, Kinesis) - Enrichment connections (Https for
$https, Cluster for$lookup)
-
Create each connection:
atlas-streams-build→resource: "connection"for each- Let the tool elicit missing sensitive fields (passwords, bootstrap servers)
- See connection-configs.md for type-specific schemas
-
Verify connections:
atlas-streams-discover→list-connections— confirm all createdatlas-streams-discover→inspect-connectionfor each — verify state and config
Phase 3: Processor Development
Goal: Working processor with validated pipeline.
Pre-Deployment Connection Validation (MANDATORY)
BEFORE creating any processor, you MUST validate all connections referenced in your pipeline. This prevents silent failures and confusion about data destinations.
Step 1: List all connections in workspace
atlas-streams-discover → action: "list-connections", workspaceName: "<your-workspace>"
Verify all required connections exist.
Step 2: Inspect EACH connection referenced in pipeline
For EVERY connectionName in your pipeline (source, sink, enrichment), inspect it:
atlas-streams-discover → action: "inspect-connection",
workspaceName: "<your-workspace>",
resourceName: "<connection-name>"
Verify for each connection:
- Connection exists and state is READY
- Connection type matches intended usage:
- Cluster: valid for
$source(change streams),$merge,$lookup - Kafka: valid for
$source,$emit - S3: valid for
$emitonly - Https: valid for
$httpsenrichment or sink - Lambda: valid for
$externalFunctiononly
- Cluster: valid for
- Connection name matches actual target (avoid confusion):
- ⚠️ BAD: connection "atlascluster" → actual target "ClusterRestoreTest"
- ✅ GOOD: connection "cluster-restore-test" → actual target "ClusterRestoreTest"
- For Cluster connections: verify the
clusterNamefield points to the intended cluster
Step 3: Present validation summary to user
Always show the user what connections will be used:
"Before creating processor '<name>', I've verified your connections:
- ✅ sample_stream_solar → Sample data (READY)
- ⚠️ atlascluster → ClusterRestoreTest (READY)
Warning: Connection name 'atlascluster' doesn't match actual cluster 'ClusterRestoreTest'
- ✅ open-meteo-api → https://api.open-meteo.com/v1/... (READY)
Proceed with processor creation?"
Step 4: Wait for user confirmation if warnings exist
If any connection name doesn't match its target, ask the user to confirm before proceeding.
Step 5: Only then create the processor
This validation workflow prevents:
- Creating processors with non-existent connections (fails immediately)
- Writing data to unexpected clusters (e.g., "atlascluster" → "ClusterRestoreTest" instead of "AtlasCluster")
- Confusion when verifying output data later
Incremental Pipeline Development
Follow incremental pipeline development — test at each step:
Step 1: Basic connectivity
[
{"$source": {"connectionName": "my-source"}},
{"$merge": {"into": {"connectionName": "my-sink", "db": "test", "coll": "step1"}}}
]
Create with autoStart: true. Verify documents flow. Stop processor.
Step 2: Add filtering
[
{"$source": {"connectionName": "my-source"}},
{"$match": {"status": "active"}},
{"$merge": {"into": {"connectionName": "my-sink", "db": "test", "coll": "step2"}}}
]
Modify pipeline (stop → modify-processor → start). Verify filtered output.
Step 3: Add transformations
[
{"$source": {"connectionName": "my-source"}},
{"$match": {"status": "active"}},
{"$addFields": {"processed_at": "$$NOW_NOT_VALID"}},
{"$project": {"userId": 1, "amount": 1, "processed_at": 1}},
{"$merge": {"into": {"connectionName": "my-sink", "db": "test", "coll": "step3"}}}
]
Remember: $$NOW is NOT valid in streaming. Use a field from the source document or omit.
Step 4: Add windowing or enrichment (if needed)
Step 5: Add error handling
- Configure DLQ:
{"dlq": {"connectionName": "my-sink", "db": "streams_dlq", "coll": "failed_docs"}} - Add
$ifNullfor optional enrichment fields - Set
onError: "dlq"on$httpsstages
Phase 4: Testing & Validation
Goal: Processor verified working correctly.
-
Confirm processor state:
atlas-streams-discover→inspect-processor— state should be STARTED
-
Run diagnostics:
atlas-streams-discover→diagnose-processor— full health report
-
Verify data flow:
- Use MongoDB
counttool on output collection — documents arriving? - Use MongoDB
findtool on output collection — data looks correct? - Use MongoDB
counttool on DLQ collection — any errors? - If DLQ has documents, use MongoDB
findtool to inspect failure reasons
- Use MongoDB
-
Classify output volume:
- See output-diagnostics.md for the full decision framework
- Alert processors: low output is expected
- Transformation processors: low output is a red flag
Phase 5: Production Deployment
Goal: Processor running at appropriate tier with monitoring.
-
Right-size the tier:
- See sizing-and-parallelism.md for tier selection
- Review
memoryUsageBytesfrom diagnostics - Consider parallelism needs for
$merge,$lookup,$https - Upgrade tier:
atlas-streams-manage→stop-processor, thenstart-processorwithtieroverride
-
Ensure DLQ is configured (mandatory for production)
-
Use descriptive processor names (e.g.,
fraud-detector,order-enricher,iot-rollup)
Debugging Decision Trees
Connection Failures
atlas-streams-discover→inspect-connection— check state- If Kafka: verify
bootstrapServersis a comma-separated string (not array) - If Cluster: verify cluster exists in project (
atlas-list-clusters) - If AWS (S3/Kinesis/Lambda): verify IAM role ARN is registered in Cloud Provider Access
- If Https: verify URL is reachable and auth headers are in connection config
Processor Startup Failures
atlas-streams-discover→diagnose-processor— check state and errors- If FAILED: read the error message in diagnostics
- Common causes:
- Invalid pipeline syntax (missing
$source, missing sink) $$NOW/$$ROOT/$$CURRENTused (not valid in streaming)- Kafka
$sourcemissingtopicfield - Referenced connection doesn't exist — validate with
list-connectionsfirst - Connection name doesn't match expected target — inspect connection to verify actual cluster/resource
- OOM — tier too small for pipeline complexity
- Invalid pipeline syntax (missing
Processing Errors (Running but DLQ filling up)
- Use MongoDB
findtool on DLQ collection — inspect error messages - Common causes:
- Schema mismatches in source data
$httpsenrichment failures (API down, auth expired)- Type errors in
$addFieldsor$projectexpressions
- Fix:
stop-processor→modify-processor(fix pipeline) →start-processor
Performance Issues (Running but slow)
atlas-streams-discover→diagnose-processor— check stats- Check
memoryUsageBytes— if near 80% of tier RAM, upgrade tier - Check if
$matchis early in pipeline (reduces downstream volume) - Check if
$httpshasparallelismsetting (increase for I/O-bound enrichment) - Check if windows have
partitionIdleTimeout(idle Kafka partitions block windows) - Consider upgrading tier or increasing stage parallelism
Operational Monitoring Cadence
Daily
- Check processor states via
atlas-streams-discover→list-processors - Verify DLQ collections aren't growing via MongoDB
counttool - Confirm output collections are receiving data
Weekly
- Run
diagnose-processorfor each production processor - Review
memoryUsageBytestrends — approaching 80%? - Check connection health across all connections
Monthly
- Evaluate tier appropriateness — over-provisioned or under-provisioned?
- Review DLQ patterns — recurring errors that need pipeline fixes?
- Consider parallelism adjustments based on throughput trends
Troubleshooting
| Symptom | Likely cause | Action |
|---|---|---|
| Processor FAILED on start | Invalid pipeline syntax, missing connection, $$NOW used | diagnose-processor → read error → fix pipeline |
| DLQ filling up | Schema mismatch, $https failures, type errors | find on DLQ → fix pipeline or connection |
| Zero output (transformation) | Connection issue, wrong topic, filter too strict | Check source health → verify connections → check $match |
| Zero output (alert) | Probably normal — no anomalies detected | Verify with known test event |
| Windows not closing | Idle Kafka partitions | Add partitionIdleTimeout to $source (e.g., {"size": 30, "unit": "second"}) |
| OOM / processor crash | Tier too small for window state | diagnose-processor → check memoryUsageBytes → upgrade tier |
| Slow throughput | Low parallelism on I/O stages | Increase parallelism on $merge/$lookup/$https |
| 404 on workspace | Doesn't exist or misspelled | discover → list-workspaces |
| 409 on create | Name already exists | Inspect existing resource or pick new name |
| 402 error on start | No billing configured | Do NOT retry. Add payment method in Atlas → Billing. Use sp.process() in mongosh as free alternative |
| "processor must be stopped" | Tried to modify running processor | manage → stop-processor first |
| bootstrapServers format | Passed as array instead of string | Use comma-separated string: "broker1:9092,broker2:9092" |
| "must choose at least one role" | Cluster connection without dbRoleToExecute | Defaults to readWriteAnyDatabase — or specify custom role |
| "No cluster named X" | Cluster doesn't exist in project | atlas-list-clusters to verify |
| IAM role ARN not found | ARN not registered in project | Register via Atlas → Cloud Provider Access |
| dataProcessRegion format | Wrong region format | See region table above. If unsure, inspect an existing workspace |
| Processor PROVISIONING for minutes | Restart cycle with exponential backoff | Wait for FAILED state, or stop → restart. Check logs for repeated error |
| Parallelism exceeded | Tier too small for requested parallelism | Start with higher tier (see sizing-and-parallelism.md) |
| Networking change needed | Networking is immutable after creation | Delete connection and recreate with new networking config |
| 401 / 403 on API call | Invalid or expired Atlas API credentials | Verify apiClientId/apiClientSecret and project-level permissions |
| 429 rate limit | Too many API calls | Wait and retry; avoid tight loops of discover calls |
Pre-Deploy Quality Checklist
Before creating a processor, verify:
Connection Validation (MANDATORY - Always do this first)
- CRITICAL: Call
atlas-streams-discover→action: "list-connections"to list all connections in workspace - CRITICAL: Call
atlas-streams-discover→action: "inspect-connection"for EACH connection referenced in pipeline - CRITICAL: Verify connection names clearly indicate their actual targets (avoid generic names like "atlascluster" pointing to "ClusterRestoreTest")
- CRITICAL: Present connection summary to user: "Connection 'X' → Actual target 'Y'" for each connection
- CRITICAL: Warn user if connection names don't match their targets and ask for confirmation
- All connections are in READY state
- Connection types match usage (Cluster for $source/$merge, Kafka for topics, etc.)
Pipeline Validation
-
search-knowledgewas called to validate sink/source field names - Pipeline starts with
$sourceand ends with$merge,$emit,$https, or$externalFunction(async) - No
$$NOW,$$ROOT, or$$CURRENTin the pipeline - Kafka
$sourceincludes atopicfield - Kafka
$sourcewith windowed pipeline includespartitionIdleTimeout(prevents windows from stalling on idle partitions) - HTTPS connections are only used in
$httpsenrichment or sink stages, not in$source - DLQ is configured (recommended for production)
-
$httpsstages useonError: "dlq"(not"fail") -
$externalFunctionstages useonError: "dlq"andexecutionis explicitly set - API auth is stored in connection settings, not hardcoded in the pipeline
Post-Deploy Verification Workflow
After creating and starting a processor:
atlas-streams-discover→action: "inspect-processor"— confirm state is STARTEDatlas-streams-discover→action: "diagnose-processor"— check for errors in the health report- Use MongoDB
counttool on