Skip to content

SaaS Kalıpları

Çok kiracılı mimari, kuyruk tabanlı işleme, ölçeklendirme matematiği

9 dk okuma

Bu bölüm kimler için: Bu bölüm, Claude CLI gömülü SaaS ürünleri geliştiren ekipler içindir. Claude’u kişisel otomasyon için kullanıyorsanız, Bölüm 16’ya atlayın.

Bir prototip oluşturuyorsunuz: claude -p’yi çağıran ve sonucu döndüren bir HTTP uç noktası. Harika çalışıyor. Sonra 10 kullanıcı aynı anda istek yapıyor ve her alt sürecin gerçek isteme dokunmadan önce başlatma için ~50K token harcadığını keşfediyorsunuz. Zarif prototipiniz pahalı bir darboğaza dönüştü.

claude -p’yi bir HTTP API’nin arkasına sardığınızda, yerel bir CLI aracını çok kiracılı bir ajan çalışma zamanına dönüştürüyorsunuz. Mimari basittir — işleri kuyruğa al, worker’lar başlat, JSON ayrıştır — ancak ekonomisi dikkat gerektirir. Her alt süreç, gerçek isteminize dokunmadan önce başlatma için ~50K token harcar ve ölçekte bu ek yük en büyük kalem haline gelir.

Buna Kim İhtiyaç Duyar

Bu bölüme ihtiyacınız var eğer şunları geliştiriyorsanız: çok kiracılı izolasyon (kullanıcı başına oturumlar), kullanıcı başına kotalar (bütçe takibi), denetim kaydı (kim ne sordu) veya hizmet olarak Claude (CLI’ı API ile sarmalama). 50 kuruluşu yöneten bir kod inceleme SaaS’ı, müşteriler arasında bağlam sızıntısını önlemek için kiracı başına oturumlar kullandı.

Mimari

CLI üzerine kurulu bir SaaS backend’i tek bir istek yaşam döngüsünü takip eder. İstemci asla Claude ile doğrudan iletişim kurmaz — API katmanınız kimlik doğrulama, bütçeleme ve kuyruğa almayı yönetirken, worker’lar alt süreç yaşam döngüsünü yönetir.

Client -> HTTP API -> Queue -> Worker -> claude -p -> Parse JSON -> Return
|
Session Store
(kullanıcı başına session_id'ler)

İşte koddaki istek yaşam döngüsü. runClaude sarmalayıcısı alt süreç çağrısını yönetir ve ayrıştırılmış JSON zarfını döndürür:

import { execFileSync } from 'child_process';
function runClaude(prompt, { sessionId, budget = 0.50, schema } = {}) {
const args = ['-p', prompt, '--output-format', 'json',
'--max-budget-usd', String(budget),
'--permission-mode', 'bypassPermissions'];
if (sessionId) args.push('--resume', sessionId);
else args.push('--no-session-persistence');
if (schema) args.push('--json-schema', JSON.stringify(schema));
const output = execFileSync('claude', args, {
encoding: 'utf-8', timeout: 120_000,
env: { ...process.env, CLAUDECODE: '' },
});
const data = JSON.parse(output);
if (data.is_error) throw new Error(`Claude error (${data.subtype}): ${data.result}`);
return data;
}

API katmanı kimlik doğrulamasını doğrular, kullanıcının bütçesini kontrol eder, işi kuyruğa alır ve ardından bir worker runClaude’u çağırır. Worker, JSON zarfını ayrıştırır, result, total_cost_usd ve session_id’yi çıkarır, sonucu istemciye döndürür ve faturalama için maliyeti kullanıcının toplam hesabına kaydeder.

Oturum Yönetimi

Çok kiracılı bir sistemde, her kullanıcının kendi konuşma durumuna ihtiyacı vardır. Oturum kimliklerini veritabanınızda kullanıcı başına saklayın ve sonraki isteklerde --resume’a iletin:

async function getOrCreateSession(userId, prompt) {
const session = await db.getActiveSession(userId);
let result;
if (session && session.age < MAX_SESSION_AGE) {
result = runClaude(prompt, { sessionId: session.sessionId });
} else {
result = runClaude(prompt);
await db.storeSession(userId, result.session_id);
}
await db.incrementCost(userId, result.total_cost_usd);
return result;
}

Burada birbirini dışlayan iki strateji var. --resume ile konuşma devamlılığı elde edersiniz ancak oturumlar diskte her biri 50-500 KB olarak birikir. --no-session-persistence ile disk yazması olmayan durumsuz bir mimari elde edersiniz ancak konuşmayı devam ettirme yolu yoktur. Ürün başına birini seçin — aynı kullanıcı akışı için karıştırılamazlar.

Maksimum oturum yaşı veya tur sayısı uygulayın, ardından yeni bir oturum başlatın. Bu olmadan, bağlam sınırsız büyür ve sonraki her tur daha fazla token maliyeti taşır.

Maliyet Amortismanı

Her claude -p alt süreci, gerçek isteminizi işlemeden önce sistem istemini, CLAUDE.md’yi ve MCP araç tanımlarını yükler. Minimum ek yük ~16K token’dır (MCP sunucu yok); aktif MCP sunucularıyla, her araç tanımı 200-500 token eklediği için başlatma ~50K token’a ulaşabilir.

Ölçekte Başlatma Ek Yükü (Opus)

Günlük İstekBaşlatma maliyetiNot
100$1.60/günErken ürünler için kabul edilebilir
1.000$16/günBaşlatma maliyeti birçok SaaS marjını aşar
10.000$160/günBu ölçekte amortisman zorunludur
Try This

Gerçek başlatma ek yükünüzü ölçün:

time claude -p “Hi” —output-format json —tools "" | jq ‘{cost: .total_cost_usd, cached: .usage.cache_read_input_tokens, created: .usage.cache_creation_input_tokens}’

O süre ve maliyet, istek başına minimum ek yükünüzdür. Şimdi beklenen eşzamanlı kullanıcı sayınızla çarpın. Ekonomi hala uygulanabilir mi?

Başlatma maliyetini azaltan üç strateji (gerçek dünya etkisine göre sıralı):

Kalıcı stream-json modu, başlatma maliyetini bir kez öder ve stdin aracılığıyla istemler besler. Bir fintek SaaS’ı bu kalıbı günde 10K+ istek için kullandı ve istek başına başlatma maliyetini $0.02’den neredeyse sıfıra düşürdü. Yüksek verimli hizmetler için en uygun:

Terminal window
claude --output-format stream-json --input-format stream-json --verbose
# stdin aracılığıyla istem besle, stdout'tan yanıtları oku

Oturum devam ettirme, ilk istekte başlatma maliyetini öder, ardından sonraki çağrılarda neredeyse sıfır ek yük olur. Konuşma tabanlı ürünler için en uygun:

Terminal window
# İlk istek -- başlatma maliyetini öder
RESULT=$(claude -p "Hello" --output-format json --permission-mode bypassPermissions)
SESSION=$(echo "$RESULT" | jq -r '.session_id')
# Sonraki istekler -- neredeyse sıfır başlatma ek yükü
claude -p "Follow up" --resume "$SESSION" --output-format json \
--permission-mode bypassPermissions

Kararlı sistem istemleri, cache’i kullanır. Her istek aynı --system-prompt dizesini kullandığında, cache isabetleri başlatma token’larında %90 tasarruf sağlar:

Terminal window
claude -p "$USER_PROMPT" \
--system-prompt "You are a code review assistant for Acme Corp." \
--output-format json --no-session-persistence \
--permission-mode bypassPermissions

Ölçeklendirme Kalıpları

Ölçeklendirme Hususları

BoyutKısıtAzaltma
BellekClaude süreci başına ~200 MB (10 worker = 2 GB, 50 worker = 10 GB)Worker havuzunu mevcut RAM’e göre boyutlandırın
EşzamanlılıkSınırsız başlatmalar sunucunun belleğini tüketirEşzamanlılık sınırlayıcılı bir iş kuyruğu kullanın (Bull, BullMQ, Bee-Queue)
DiskOturumlar her biri 50-500 KB olarak birikir (günde 10K = günde 5 GB’a kadar)—no-session-persistence kullanın veya temizlik cron’ları çalıştırın
Hız sınırlamaYerleşik kullanıcı başına kısıtlama yokKuyruğa almadan önce API katmanınızda uygulayın
Model yönlendirmeOpus, Sonnet’in 5 katı maliyetindedirBasit görevleri —effort low ile Sonnet’e yönlendirin, Opus’u karmaşık muhakeme için ayırın

Worker kuyruğu, temel ölçeklendirme ilkelidir. Eşzamanlı Claude süreçlerini sınırlamak ve sunucunuzu bellek tükenmesinden korumak için kullanın:

import Queue from 'bull';
const claudeQueue = new Queue('claude-tasks', {
limiter: { max: 10, duration: 60_000 }
});
claudeQueue.process(async (job) => {
const { userId, prompt, sessionId } = job.data;
return runClaude(prompt, { sessionId });
});

Maliyet kontrolünü birden fazla seviyede katmanlayın. --max-budget-usd aracılığıyla istek başına tavanlar aşırı tekil çağrıları önler. API katmanınızdaki kullanıcı başına günlük limitler kötüye kullanımı önler. Model yönlendirme ucuz görevleri Sonnet’e, pahalı olanları Opus’a gönderir:

const routing = {
simple_qa: { model: 'claude-sonnet-4-6', effort: 'low' },
code_review: { model: 'claude-sonnet-4-6', effort: 'medium' },
security_audit: { model: 'claude-opus-4-6', effort: 'high' },
};

İstemcilere Akış

Gerçek zamanlı kullanıcı arayüzleri için, --output-format stream-json’ı bir SSE uç noktası üzerinden iletin. CLI, NDJSON olayları yayar ve sunucunuz text_delta olaylarını SSE çerçevelerine çevirir:

import { spawn } from 'child_process';
import { createInterface } from 'readline';
app.post('/api/stream', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
const proc = spawn('claude', ['-p', req.body.prompt,
'--output-format', 'stream-json', '--verbose',
'--include-partial-messages',
'--permission-mode', 'bypassPermissions'],
{ env: { ...process.env, CLAUDECODE: '' } });
const rl = createInterface({ input: proc.stdout });
rl.on('line', (line) => {
if (!line.trim()) return;
const event = JSON.parse(line);
if (event.type === 'stream_event') {
const delta = event.event?.delta;
if (delta?.type === 'text_delta') {
res.write(`data: ${JSON.stringify({ text: delta.text })}\n\n`);
}
} else if (event.type === 'result') {
res.write(`data: ${JSON.stringify({ done: true, cost: event.total_cost_usd })}\n\n`);
res.end();
}
});
});

stream-json çıktısı kullanırken --verbose bayrağı gereklidir. Olmadan, CLI ihtiyacınız olan akış olaylarını bastırır. --include-partial-messages bayrağı, tam mesajları beklemek yerine metin delta’larını gelir gelmez almanızı sağlar.

Gotcha

Her yeni claude -p alt süreci, gerçek isteminizi işlemeden önce ~16K-50K token’lık sistem istemi, araç tanımları ve CLAUDE.md yükler. Opus’ta günde 1.000 istekle, bu günde $16 saf başlatma ek yüküdür. Bu maliyeti istekler arasında amortize etmek için —resume, kalıcı stream-json oturumları veya kararlı —system-prompt dizeleri kullanın.

Gotcha

Kullanıcı başına oturum mimarisi, her turda bağlam biriktirir. 20. turda, her istek binlerce token’lık önceki konuşma taşıyabilir. Maksimum oturum yaşı veya tur sayısı uygulayın ve periyodik olarak yeni oturumlar başlatın — aksi takdirde istek başına maliyetiniz konuşma uzunluğuyla doğrusal olarak büyür ve sonunda bütçenizi domine eder.

Bunu Uygulamada Görün

Eksiksiz bir SaaS uygulamasını görün — Hono REST API, SSE akışı, kayıt kalıbı, SQLite kalıcılığı ve eşzamanlı worktree izolasyonu — MR İnceleyici Oluşturun, Bölüm 7: Tam Mimari.

Now Do This

Alt süreç başlatma maliyetinizi ölçün: time claude -p “Hi” —output-format json —tools "". Bu, istek başına minimum gecikme ve maliyetinizdir. Çok kiracılı bir hizmet oluşturuyorsanız, bu sayı tabandır — her istek, gerçek isteminiz çalışmadan önce bile bunu öder.