Skip to Content
ConceptsResilience & Reliability

Resilience & Reliability

How Etch ensures your token launches succeed even when things go wrong.

Overview

Token launches involve multiple on-chain transactions across different protocols. Etch is designed to handle failures gracefully at every step.

Idempotency

Every launch has a unique launchId. If you accidentally submit the same launch twice (or if our job queue retries), Etch detects this and returns the existing result instead of creating duplicate tokens.

// Second request with same launchId { "status": "already_processed", "mint": "ABC123...", "pool": "XYZ789..." }

Best Practice: Always generate a unique launchId client-side (e.g., UUID) and store it before calling the API.

Transaction Retries

Solana transactions can fail for transient reasons:

  • Blockhash expired
  • Network congestion
  • RPC node issues

Etch automatically retries failed transactions with exponential backoff:

AttemptDelay
1Immediate
22 seconds
34 seconds
48 seconds
516 seconds

Retryable vs Non-Retryable Errors

Retryable:

  • Blockhash not found
  • Too many requests (429)
  • Network timeouts
  • RPC 503/504

Non-Retryable:

  • Insufficient funds
  • Invalid signature
  • Account not found
  • Program errors

Partial Failure Handling

A token launch involves multiple steps:

  1. Create SPL token mint
  2. Mint total supply
  3. Create Meteora pool
  4. Upload metadata
  5. Create vesting (optional)
  6. Create DAO (optional)

If an optional step fails (metadata, vesting, DAO), the launch continues and completes with the core token and pool. You’ll receive a webhook with partial results.

{ "event": "launch.complete", "data": { "mint": "ABC123...", "pool": "XYZ789...", "warnings": [ { "step": "vesting", "error": "Streamflow service unavailable" } ] } }

Connection Health Monitoring

Etch monitors connections to all dependencies:

  • Solana RPC — Health checked every 30 seconds
  • Database — Connection pool with automatic reconnection
  • Redis — Graceful fallback to in-memory cache

If a connection becomes unhealthy, Etch automatically reconnects on the next request.

Dead Letter Queue

When a launch fails after all retries, it’s saved to a dead letter queue (DLQ) for manual review. The DLQ contains:

  • Original launch configuration
  • Error message and stack trace
  • Number of retry attempts
  • Timestamp

Contact support to:

  • View DLQ items
  • Retry failed launches
  • Get refunds for unrecoverable failures

Timeouts

All operations have strict timeouts to prevent hung requests:

OperationTimeout
Transaction confirmation60 seconds
Webhook delivery10 seconds
RPC requests30 seconds
Database queries10 seconds

Rate Limiting

Rate limits prevent abuse and ensure fair access:

EndpointLimit
General API60/min
Auth endpoints10/min
Launch endpoint5/hour
Webhooks10/hour

Rate limiting uses a sliding window algorithm. When limits are exceeded:

HTTP 429 Too Many Requests Retry-After: 60

Note: Rate limits apply per wallet AND IP address to prevent bypass attacks.

Best Practices

1. Implement Webhook Handlers Properly

// ✅ Good: Acknowledge immediately, process async app.post("/webhook", (req, res) => { res.status(200).send("OK"); processWebhookAsync(req.body); }); // ❌ Bad: Blocking processing app.post("/webhook", async (req, res) => { await processWebhook(req.body); // May timeout res.status(200).send("OK"); });

2. Store Launch IDs Before Calling API

// ✅ Good: Store first, then call const launchId = crypto.randomUUID(); await db.launches.create({ id: launchId, status: "pending" }); const result = await etch.launch({ launchId, ... }); await db.launches.update({ id: launchId, ...result });

3. Handle Partial Success

if (result.warnings?.length > 0) { // Core launch succeeded but optional features failed log.warn("Partial success", result.warnings); // Maybe retry failed steps manually }

4. Monitor the Health Endpoint

const health = await fetch("https://etch.film.fun/api/health"); if (health.status === "unhealthy") { // Delay launches until recovered await delay(60000); }
Last updated on