Forge Backend Infrastructure

website·Indexed 31 days ago

https://tryforge.dev

An in-process infrastructure library providing eight backend primitives—including Key-value stores, Queues, Pub/sub, Blob storage, Auth, and Rate limiting—with a versioned contract across Rust, JavaScript, Python, and Go. Forge offers cross-language API stability, PostgreSQL-centered production models, and integration recipes for frameworks like Axum, Hono, Express, FastAPI, and Django ASGI.

Tokens
37.3K
Snippets
117
Records
175
Agent score
54%

What's inside Forge

  1. Overview of Forge backend primitives

    Forge provides a unified contract across Rust, JavaScript, Python, and Go to access eight core backend primitives. It uses PostgreSQL as the shared durable backend, though memory can be used for process-local testing and filesystems or S3-compatible stores can be used for blobs.
  2. Understand Forge's cross-language API stability policy

    Starting with version 1.1.0, Forge coordinates releases across Rust, JavaScript, Python, and Go. Within the 1.x release cycle, Forge guarantees that public APIs will not be removed or renamed, documented behavior or error classifications will not change, and configuration interpretations will remain consistent. Breaking changes are reserved for the 2.0 release. Deprecations are announced in release notes and documentation, and where practical, will trigger warnings for at least one release before being removed at the next compatibility boundary.
  3. Understand Forge architectural scope and ownership

    Forge is an in-process infrastructure library for application backends (Rust, JS, Python, Go) that uses PostgreSQL as the durable system of record. It provides bounded primitives but does not manage application-level concerns.

    Forge owns:

    • Primitive APIs and cross-language contracts
    • PostgreSQL/memory behavior, filesystem and S3 blob adapters
    • Schema, migrations, validation, and runtime diagnostics
    • Queue leases, retry state, dead-letter operations, and worker mechanics
    • Bounded CloudEvents, trace-context, and invalidation encodings
    • Server-side config caches and invalidation publication

    The Application owns:

    • Protocol surfaces (HTTP, RPC, GraphQL, MCP)
    • Business tables, domain transactions, and authorization policy
    • Deployment order, process signals, and pool budgets
    • Worker handlers, side-effect idempotency, and audit records
    • Transport delivery, telemetry export, and secret storage
    • Frontend frameworks and client-side state/refetch logic
  4. Understand Forge Event Delivery architecture

    Forge is a backend library that encodes bounded invalidation hints. It does not manage HTTP routes, WebSockets, or client-side refetching. The standard flow is: the backend commits authoritative state, publishes an invalidation hint, and an application-owned transport forwards that hint to connected clients. Clients receiving a hint should then fetch the authoritative state again. The system is designed so that loss, duplication, delay, or reordering of hints does not affect correctness.
  5. Understand Forge primitive behavioral contracts

    Forge maintains consistent method shapes across different backends, but durability and process scope vary by backend. The behavioral contract for primitives defines the guarantees for consistency, ordering, duplication, expiry, retries, outages, and multi-process interactions. For a runtime view of these constraints, developers should check the backendCapabilities of the specific backend being used.
  6. Schedule delayed tasks and cron jobs with Forge

    Forge allows you to schedule one-time delayed tasks using schedule_at (or .at() in Rust) and recurring tasks using schedule_cron (or .cron() in Rust).

    Important: Schedules only fire when the scheduler is ticked. The loop that ticks the scheduler is also the recommended location to run Forge's maintenance sweep. Refer to the Operations documentation for the specific loop implementation required on every replica.

    # Schedule a one-time task to expire a link in one hour
    await forge.schedule_at(now_ms + 3_600_000, "expire", json.dumps({"slug": slug}))
    
    # Schedule a daily report at midnight
    await forge.schedule_cron("nightly-report", "0 0 * * *", "reports", "{}")
    use std::time::{Duration, SystemTime};
    use forgelib::ScheduleOpts;
    
    // Schedule a one-time task to expire a link in one hour
    let when = SystemTime::now() + Duration::from_secs(3600);
    forge.schedule().at(when, "expire", payload.into(), ScheduleOpts::new()).await?;
    
    // Schedule a daily report at midnight
    forge.schedule().cron("nightly-report", "0 0 * * *", "reports",
        b"{}".to_vec().into(), ScheduleOpts::new()).await?;
  7. Manage user sessions and authentication middleware

    Use validateSession in middleware to resolve a bearer token or session cookie to a user ID. To log a user out, use revokeSession to invalidate the token immediately so it no longer resolves to a user.
    // Rust Example
    // Middleware: resolve bearer token to a session, else 401
    let Some(session) = forge.auth().validate_session(bearer).await? else {
        return unauthorized();
    };
    let user_id = session.user_id;
    
    // Logout: revoke the session so the token stops resolving
    forge.auth().revoke_session(bearer).await?;
  8. Export Forge metrics to Prometheus

    Forge provides built-in metrics for operations, pool use, retries, queue/worker state, and more. Use renderPrometheus() (or language equivalent) to emit Prometheus-formatted text. This does not require a separate collector or exporter installation.

    Note: Forge uses fixed low-cardinality labels. High-cardinality data like user IDs, job IDs, or model outputs are never used as labels or span attributes to prevent metric explosion.

  9. Implement API keys and one-time tokens

    API-key secrets are returned once; Forge stores only the hash. Implement bounded expiries, explicit scopes, and minimal non-secret metadata. Enforce owner and scope checks in the application policy after verification.

    One-time tokens must be purpose-scoped, expiring, hashed, and atomically consumed. Use them for opaque return state or record IDs rather than authorization policy. Tokens cannot be replayed for different purposes or recovered once consumed.

  10. Offload slow work to a background queue

    Improve request latency by performing only lightweight operations (like incrementing a counter) inline and offloading heavy processing to a queue. Workers lease jobs from the queue and must acknowledge (ack) success or negatively acknowledge (nack) failure to trigger a retry.
    // In the request handler: cheap now, the rest later
    await forge.kvIncr(`clicks:${slug}`, 1);
    await forge.queue<{ slug: string } ("clicks").enqueue({ slug }, { maxAttempts: 3 });
    
    // In the worker: process the job
    await forge.worker<{ slug: string }>( "clicks", async (job) => {
      await handle(forge, job.payload);
    });
  11. Implement typing indicators and user presence

    Typing indicators are transient and should be published to a topic without being stored. User presence is managed by setting a KV key with a short TTL (e.g., 30 seconds) that is refreshed via a heartbeat endpoint.
    // Typing indicator (Live only)
    app.post("/api/rooms/:room/typing", async (c) => {
      await forge.topic(`chat:${c.req.param("room")}`).publish({ type: "typing", userId });
      return c.body(null, 204);
    });
    
    // Presence heartbeat
    app.post("/api/heartbeat", async (c) => {
      const userId = await requireUser(c);
      await forge.kvSet(`presence:${userId}`, "1", 30); // expires in 30s
      await forge.topic("presence").publish({ userId, online: true });
      return c.body(null, 204);
    });
  12. Implement user authentication and session management with Forge

    Forge provides primitives for password hashing, session creation, and rate limiting. Use forge.rate_limit_check to prevent brute-force attacks on signup/login, forge.hash_password and forge.verify_password for security, and forge.create_session to manage user state. Use forge.kv_set with the nx=True (set if not present) parameter to ensure email uniqueness during registration.
    # Example Signup Logic
    @api.post("/api/signup", status_code=201)
    async def signup(request: Request, body: Credentials) -> dict[str, Any]:
        forge = request.app.state.forge
        email = body.email.strip().lower()
    
        # Rate limiting
        limit = await forge.rate_limit_check("links-auth", email, 20, 60.0, True)
        if not limit.allowed:
            raise HTTPException(429, "too many attempts")
    
        user = {"id": str(uuid.uuid4()), "email": email, 
                "password_hash": await forge.hash_password(body.password)}
        
        # Atomic check if email exists
        if not await forge.kv_set(user_email_key(email), json.dumps(user), None, True):
            raise HTTPException(409, "email already registered")
        
        token = await forge.create_session(user["id"], 1800.0, 604800.0)
        return {"token": token, "user": {"id": user["id"], "email": email}}