Cloudflare Workers'a WASM Görsel Yeniden-Boyutlama Modülü Yüklemek
Rust + WASM ile yazılmış bir görsel boyutlama handler'ının Cloudflare Workers'ın binary, bellek ve CPU tavanlarına sığıp sığmayacağını inceleyen keşif.
Body’den JPEG alıp yeniden boyutlandırılmış JPEG döndüren bir POST /resize?w=800&q=85 handler’ı, Cloudflare Workers + WASM’ın bir görsel hattı sunucusu olarak en sade, oyuncak olmayan stres testidir. Tasarım üç edge-platform limitine aynı anda yüklenir: derlenmiş binary boyutu, isolate başına bellek ve istek başına CPU süresi. Sırayla okunduğunda yayınlanmış limitler sorunun büyük kısmını zaten çözer. Free tier tek başına CPU süresinden elenir; Paid tier’da ise tasarım, ikinci bir codec’e pek yer bırakmayan bir bundle bütçesi içinde, istek başına tek görsel için iş görür.
Çerçeve WebAssembly 101 yazısındaki 3. bahisten geliyor: WASM’ın edge’de taşınabilir hesaplama primitifi olması. O çerçeve burada bozulmuyor; yeniden türetmeyeceğim. Soru tersi yönde ilerliyor: o primitife gerçek bir görsel codec’i yüklediğinizde ve body-in, body-out trafik gönderdiğinizde ne olur.
İstek Yolu
Edge PoP, TLS’i sonlandırır ve bir V8 isolate’ına yönlendirir. WASM örneğini doğrudan bu isolate barındırır. İstek body’sinin, çözülmüş piksel buffer’ın ve kodlanmış yanıtın her baytı, isolate’ın eşzamanlı çağrılarla paylaştığı tek bir 128 MB bütçesinin içinde yer alır.
Dokümanlardaki Limitler
Binary boyutu. Cloudflare, Free tier için 3 MB, Paid tier için 10 MB gzip sonrası limit yayınlar; her ikisinde de sıkıştırmadan önce 64 MB tavan vardır. Deploy anında önemli olan sayı sıkıştırılmış olandır ve wrangler deploy --outdir bundled/ --dry-run bunu Total Upload: N KiB / gzip: M KiB olarak yazdırır. Bundle içindeki sıkıştırılmamış wasm dosyası gzip raporunun düşündürdüğünden belirgin biçimde büyük olabilir. Worker size limits sayfasına bakın.
Isolate başına bellek. Her isolate, JavaScript heap’i ve WebAssembly ayırmaları dahil 128 MB’a kadar kullanabilir. Cloudflare bu bütçeyi isolate’a bağlar: tek bir isolate birçok eşzamanlı isteği işler ve bu isteklerin tüm ayırmaları aynı 128 MB zarfında yer alır. Bkz. Memory per isolate.
İstek başına CPU süresi. Free tier, HTTP isteği başına 10 ms CPU verir. Paid tier bunu 30 saniyelik varsayılana taşır ve 5 dakikaya kadar yapılandırılabilir. CPU süresi ağ beklemesini kapsamaz; yani tüm yeniden-boyutlama maliyeti doğrudan bu bütçeye düşer. Bkz. CPU time.
Başlangıç süresi. Bir Worker, üst-düzey kodunu 1 saniye içinde ayrıştırıp yürütmek zorundadır; aksi halde wrangler deploy’u 10021 hatasıyla reddeder. Büyük WASM bundle’ları bu bütçeyi yer çünkü ayrıştırıcı başlangıçta tüm modülü gezmek zorundadır. Bu, çağrı başına bir çalışma zamanı maliyeti değil, deploy anı doğrulamasıdır. Bkz. Worker startup time.
Isolate modeli. Workers, Chromium ve Node.js’in kullandığı motor olan V8 üzerinde çalışır. WASM, V8 isolate’ı içinde WebAssembly.instantiate() ile yüklenir; altta bir WASI çalışma ortamı yoktur. Cloudflare kendi dokümanında WASI desteğini deneysel olarak, yalnızca bazı syscall’lar uygulanmış şekilde tanımlar. Bir görsel handler’ı için bu uygundur çünkü iş byte buffer’lar üzerinde saf hesaplamadır; dosya sistemi ya da ağ gerekmez. Bkz. How Workers works ve WebAssembly runtime APIs.
Kurulum
workers-rs yolu belgelidir ve yayın çizgisi aktiftir; v0.8.1, 17 Nisan 2026’da yayınlandı. wasm32-unknown-unknown üçlüsünü hedefleyin, şablondan üretin ve JS shim’ini worker-build’e bırakın:
rustup target add wasm32-unknown-unknown
cargo install cargo-generate
cargo generate cloudflare/workers-rs
Görsel-işleme bağımlılıklarını ekleyin. photon-rs şu an crates.io’da 0.3.3 yayınlıyor; bu sürümü sabitleyin. image crate’i photon-rs tarafından transitif olarak çekilir (photon-rs 0.3.3 kendi Cargo.toml’unda image ^0.24.8 sabitler), dolayısıyla doğrudan bağımlılık olarak eklemek çift-sürüm bundle riski yaratır. photon-rs’in açmadığı bir encoder gerekmedikçe doğrudan pin’i düşürün:
[dependencies]
worker = "0.8"
photon-rs = "0.3"
wrangler yapılandırması Worker’ı baştan Paid-tier davranışına sabitler. cpu_ms = 100 ayarı kasıtlıdır; maliyet zarfını 30 saniyelik varsayılanın altına saklamak yerine erken ortaya çıkarır:
name = "wasm-resize"
main = "build/worker/shim.mjs"
compatibility_date = "2026-04-22"
[build]
command = "cargo install -q worker-build && worker-build --release"
[limits]
cpu_ms = 100
R2 yok, KV yok, auth yok. Kapsam body-in, body-out.
Handler
Handler, istek body’sini bir PhotonImage’a çözer, en-boy oranını korumak için width sorgu parametresinden hedef yüksekliği hesaplar, Lanczos3 çekirdeği ile yeniden boyutlandırır ve 85 kalitesinde JPEG olarak yeniden kodlar:
use worker::*;
use photon_rs::{
native::open_image_from_bytes,
transform::{resize, SamplingFilter},
PhotonImage,
};
#[event(fetch)]
pub async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
Router::new()
.post_async("/resize", |mut req, _ctx| async move {
let url = req.url()?;
let w: u32 = url
.query_pairs()
.find(|(k, _)| k == "w")
.and_then(|(_, v)| v.parse().ok())
.unwrap_or(800);
let body = req.bytes().await?;
// Çöz -> yeniden boyutlandır -> yeniden kodla. Her byte,
// eşzamanlı çağrılarla paylaşılan 128 MB isolate bütçesi içindedir.
let img: PhotonImage = open_image_from_bytes(&body)
.map_err(|e| Error::RustError(format!("decode: {e:?}")))?;
let h = ((img.get_height() as f32) * (w as f32)
/ (img.get_width() as f32)) as u32;
let resized = resize(&img, w, h, SamplingFilter::Lanczos3);
let out = resized.get_bytes_jpeg(85);
let mut headers = Headers::new();
headers.set("content-type", "image/jpeg")?;
Ok(Response::from_bytes(out)?.with_headers(headers))
})
.run(req, env)
.await
}
RouteContext üzerindeki .data() ve .get_env() erişimcileri workers-rs’in daha eski sürümlerinde doğrudan alan erişimi lehine eskitildi; yukarıdaki örnek her ikisinden de kaçınır. Bu kodun üstüne bir şey inşa etmeden önce open_image_from_bytes, get_bytes_jpeg ve SamplingFilter::Lanczos3 imzalarını Cargo.toml’da sabitli photon-rs sürümüne karşı yeniden kontrol edin; bir imza kaymışsa shim trait’le örtmek yerine çağrı yerini düzeltin.
Limit Noktaları
Bunlar dokümanlara bağlı tahminlerdir; POC doğrulayacak ya da düzeltecektir.
Binary boyutu
photon-rs; image ^0.24.8, imageproc ^0.23.0, palette, rusttype, perlin2d ve rand’ı çeker. Transitif graf küçük değildir. wasm-opt -Oz ve gzip sonrası bundle muhtemelen tek haneli MB’larda kalacaktır. Free tier’da (3 MB) buna yer yoktur. Paid tier (10 MB) gerçekçidir ama dardır; herhangi bir kardeş crate eklerseniz özellikleri kırpmayı bekleyin. Yaklaşıma bağlanmadan önce gerçek gzip boyutunu wrangler deploy --dry-run ile doğrulayın.
İstek başına bellek
4000 x 3000 bir JPEG, yaklaşık 48 MB RGBA8’e çözülür (4000 x 3000 x 4). Yeniden-boyutlama scratch’i bunu kısa süreliğine iki katına çıkarabilir. 128 MB tavanı aynı isolate’taki eşzamanlı çağrılar arasında paylaşılır; bu yüzden eşzamanlı iki 12-megapikselli çözme, tek tek sığsa bile tahliye riski taşır. Bir kullanıcı-yükleme uç noktasında ya edge’de azami megapiksel sayısını dayatın ya da Worker’ın önüne isolate başına eşzamanlılığı kısan bir kuyruk koyun.
CPU süresi
Free tier’ın 10 ms CPU bütçesi tüm tasarımı diskalifiye eder. Çok-megapikselli bir görselin Lanczos3 yeniden-boyutlaması, hiçbir gerçekçi isolate’ta 10 ms’de bitmeyecektir. Paid’de 30 saniyelik varsayılan tek bir görsel için bol bol yeter; cpu_ms = 100 ile başlamak handler’ı dürüst tutmaya zorlar. POC çalışıp görsel başına gerçek maliyeti ortaya koyduğunda limiti o ölçümün gerektirdiği sayıya yükseltin.
Cold start
Üst-düzey ayrıştırması 1 saniyelik bütçeyi aşan bir bundle deploy anında düşer; yani çözüm modülün yerleşimindedir. Başlatmayı handler içinde tutun ve arama tablolarını ya da font atlaslarını modül başlangıcında yüklemekten kaçının.
CF Workers + WASM’ın Yanlış Araç Olduğu Durumlar
Üç iş profili başka bir platforma aittir.
Büyük kaynak görseller ya da batch işler. Girdiler rutin olarak yaklaşık 8-10 megapikseli aşarsa ya da iş bir klasör üzerinde batch tipi çalışıyorsa, 128 MB’lık paylaşılan isolate esnemez. S3 + Lambda, efemeral /tmp deposuyla tek-görsel işleri daha büyük bellek zarfında karşılar. Fargate ya da worker döngüsü çalıştıran ECS, batch işleri karşılar. İkisi de Worker’ın kaçındığı bir cold-start maliyeti öder ama ikisinin de bellek tavanı bu yüke göre ölçeklidir.
Çıktı format çeşitliliği. AVIF, HEIC ve hareketli WebP encoder’ları bundle’a belirgin byte ekler. Bunları photon-rs üzerine yığmak 10 MB sıkıştırılmış tavanı patlatacaktır. Birden çok çıktı formatı gerekiyorsa yönetilen yol Cloudflare Images; kendi barındırdığınız yol bir CDN’in arkasındaki container.
Yeniden-boyutlamanın ötesinde hat aşamaları. Görsel üzerinde yüz tanıma, OCR ya da ML inference farklı bir hesaplama profilidir. Workers AI, modelleri bir HTTP arayüzünün arkasında sunar; daha ağır olan her şey için bir GPU task runner uygundur. CPU’ya bağlı bir Worker’a inference sıkıştırmaya çalışmak, WASM bundle’ının kırpılabileceğinden daha hızlı CPU bütçesi yakar.
Kapanış
Sınır dar ve kontrol edilebilir: Paid tier, istek başına tek görsel, tek bir çıktı format ailesi, uzun kenarı yaklaşık 3000 px’e kadar fotoğraflar. Bu sınırın içinde Cloudflare Workers + workers-rs + photon-rs, üretimde bir yeniden-boyutlama uç noktasına ucuz bir yoldur. Dışında kalan her durumda, daha fazla Rust yazmadan önce S3 + Lambda, Fargate ya da yönetilen bir görsel ürününe uzanın.
Kaynaklar
- Cloudflare Workers platform limits - Free ve Paid tier’larda binary boyutu, bellek, CPU süresi ve başlangıç limitleri.
- Cloudflare Workers Rust language guide -
cargo generate+worker-buildyolunun resmi anlatımı. - Cloudflare Workers WebAssembly reference -
WebAssembly.instantiate()modeli, WASI durumu vewasm-optrehberi. - How Workers Works - Cloudflare edge’inde V8 isolate modeli ve eşzamanlılık anlamı.
- wrangler configuration reference -
[limits]bloğu dahilwrangler.tomlvewrangler.jsonc. - workers-rs repository - Rust ile yazılan Worker’lar için aktif crate; 17 Nisan 2026 itibarıyla v0.8.1.
- workers-rs release notes - v0.7
RouteContexteskitmeleri dahil sürüm geçmişi. - photon-rs API docs - Handler’ın kullandığı native modül için crate dokümantasyonu.
- photon-rs repository - Desteklenen görsel formatları ve render kütüphanesinin kaynağı.
- image crate documentation - Encoder ve decoder özellik bayrakları bundle boyutunu şekillendiren üst-akış image crate’i.
İlgili yazılar
Stack'ten bağımsız bir WebAssembly haritası (tarayıcıda performans, sunucuda WASI, edge'de compute) hangi konuşmanın hangi bahisten gittiğini gösterir.
Edge computing, AI-destekli development ve platform entegrasyonunun frontend tooling'de neyi değiştirdiği ve hangi vaatlerini yayımlanmış rakamların desteklemediği.
Nub ve Vite+, 2026'nın oxc tabanlı iki Rust araç zinciri; rakip gibi görünüp öyle değiller. Hangi ikilinin hangi repoda yeri olduğuna dair net bir kural.
Bir keşif tezi: event-driven sistemlerde vendor lock-in runtime'da değil bus topolojisinde yaşar; wasmCloud ve NATS bus'ı taşınabilir kılıyor.
Global uygulamalar için AWS edge computing çözümlerini seçme ve uygulama üzerine pratik örnekler ve maliyet optimizasyonu stratejileri içeren kapsamlı teknik rehber.