Porównanie Pactown Quadlet z Cloudflare Workers jako platformy edge/serverless.
| Aspekt | Pactown Quadlet | Cloudflare Workers |
|---|---|---|
| Model | Self-hosted VPS | Edge serverless |
| Koszt | €5-20/mc (VPS) | $5/mc + $0.50/M req |
| Latency | 20-50ms (single region) | 5-15ms (edge) |
| Cold start | 0ms (always hot) | 0-50ms |
| CPU limit | Unlimited | 50ms/10ms |
| Memory | Configurable (GB) | 128MB |
| Execution | Unlimited | 30s/15min |
| WebSocket | Full support | Limited |
| State | Redis/SQLite/Postgres | KV/D1/Durable Objects |
| Self-hosted | ✓ | ✗ |
| GDPR | Full control | CF datacenters |
┌─────────────────────────────────────────────────┐
│ Hetzner VPS │
│ ┌─────────────────────────────────────────┐ │
│ │ Traefik Proxy │ │
│ │ - Let's Encrypt TLS │ │
│ │ - Rate limiting │ │
│ │ - Load balancing │ │
│ └────────────────┬────────────────────────┘ │
│ │ │
│ ┌────────────────┼────────────────────────┐ │
│ │ Quadlet Containers │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │email │ │ api │ │notify│ │ │
│ │ │worker│ │gateway│ │websock│ │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ Redis │ PostgreSQL │ SQLite │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Cloudflare Edge Network │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ 300+ Global PoPs (Points of Presence) │ │
│ │ │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │ WAW │ │ FRA │ │ NYC │ │ SIN │ ... │ │
│ │ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │ │
│ │ └────────┴────────┴────────┘ │ │
│ │ V8 Isolates │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ KV Store │ D1 (SQLite) │ R2 (S3) │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Cloudflare Worker:
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === '/api/hello') {
return new Response(JSON.stringify({ hello: 'world' }), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not found', { status: 404 });
}
}
Pactown (FastAPI):
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/hello")
async def hello():
return {"hello": "world"}
Quadlet deployment:
# Example using a README.md-based service (recommended pattern)
pactown quadlet deploy ./examples/api-gateway-webhooks/README.md \
--domain example.com \
--subdomain api \
--tenant gateway \
--tls
Cloudflare KV:
await env.MY_KV.put('key', 'value');
const value = await env.MY_KV.get('key');
Pactown (Redis):
import redis
r = redis.Redis.from_url(os.getenv("REDIS_URL"))
r.set('key', 'value')
value = r.get('key')
Cloudflare Durable Objects:
export class Counter {
constructor(state) {
this.state = state;
}
async fetch(request) {
let count = await this.state.storage.get('count') || 0;
count++;
await this.state.storage.put('count', count);
return new Response(count.toString());
}
}
Pactown (SQLite):
import sqlite3
conn = sqlite3.connect('/data/state.db')
@app.post("/counter/{id}")
async def increment(id: str):
cursor = conn.execute(
"INSERT INTO counters (id, count) VALUES (?, 1) "
"ON CONFLICT(id) DO UPDATE SET count = count + 1 "
"RETURNING count",
(id,)
)
count = cursor.fetchone()[0]
conn.commit()
return {"count": count}
# Pactown deployment
pactown quadlet deploy ./examples/email-llm-responder/README.md \
--domain mail.example.com \
--subdomain email
# Pactown deployment
pactown quadlet deploy ./examples/realtime-notifications/README.md \
--domain notify.example.com \
--subdomain ws
| Pactown | Cloudflare | |
|---|---|---|
| Base | €5 (Hetzner CX22) | $5 (Workers Paid) |
| Requests | $0 | $0.50 (1M incl.) |
| KV/Redis | €0 (self-hosted) | $0.50/M reads |
| Total | €5 | ~$6 |
| Pactown | Cloudflare | |
|---|---|---|
| Base | €20 (Hetzner CX42) | $5 |
| Requests | $0 | $49.50 (99M × $0.50) |
| KV/Redis | €5 (managed Redis) | $50+ |
| Total | €25 | ~$105 |
| Pactown | Cloudflare | |
|---|---|---|
| Base | €50 (dedicated) | $5 |
| Requests | $0 | $50 |
| DO/Database | €20 (PostgreSQL) | $500+ (DO) |
| Total | €70 | ~$555 |
Można łączyć oba podejścia:
┌─────────────────────────────────────────────────────────────┐
│ Cloudflare Edge │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ - DDoS protection │ │
│ │ - Global CDN │ │
│ │ - Simple routing Worker │ │
│ └────────────────────────┬────────────────────────────┘ │
└───────────────────────────┼─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Pactown VPS (Origin) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ - Long-running tasks │ │
│ │ - WebSocket connections │ │
│ │ - LLM integrations │ │
│ │ - Complex state management │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Cloudflare Worker (proxy):
export default {
async fetch(request, env) {
// Quick edge logic
if (isBot(request)) {
return new Response('Blocked', { status: 403 });
}
// Proxy to Pactown origin for heavy lifting
return fetch('https://api.pactown-origin.com' + new URL(request.url).pathname, {
method: request.method,
headers: request.headers,
body: request.body
});
}
}
Wybierz Pactown gdy:
Wybierz Cloudflare Workers gdy:
Hybrid gdy: