Türkçe

JavaScript'in asenkron bağlamını ve istek kapsamlı değişkenleri nasıl etkili bir şekilde yöneteceğinizi keşfedin. AsyncLocalStorage, kullanım alanları, en iyi uygulamaları ve asenkron ortamlarda bağlamı koruma alternatifleri hakkında bilgi edinin.

JavaScript Asenkron Bağlamı: İstek Kapsamlı Değişkenleri Yönetme

Asenkron programlama, modern JavaScript geliştirmesinin, özellikle de Node.js gibi ortamlarda performans için engellemeyen G/Ç'nin çok önemli olduğu ortamlarda bir köşe taşıdır. Ancak, asenkron işlemler arasında bağlamı yönetmek zor olabilir. İşte burada JavaScript'in asenkron bağlamı, özellikle AsyncLocalStorage devreye giriyor.

Asenkron Bağlam Nedir?

Asenkron bağlam, verileri yaşam döngüsü boyunca devam eden bir asenkron işlemle ilişkilendirme yeteneğini ifade eder. Bu, birden çok asenkron çağrı arasında istek kapsamlı bilgileri (örneğin, kullanıcı kimliği, istek kimliği, izleme bilgileri) korumanız gereken senaryolar için gereklidir. Uygun bağlam yönetimi olmadan, hata ayıklama, günlük kaydı ve güvenlik önemli ölçüde daha zor hale gelebilir.

Asenkron İşlemlerde Bağlamı Koruma Zorluğu

Bağlamı yönetmeye yönelik geleneksel yaklaşımlar, örneğin değişkenleri fonksiyon çağrıları aracılığıyla açıkça geçirmek, asenkron kodun karmaşıklığı arttıkça hantal ve hataya açık hale gelebilir. Geri çağırma cehennemi ve söz dizimi zincirleri bağlam akışını gizleyebilir, bu da bakım sorunlarına ve potansiyel güvenlik açıklarına yol açar. Bu basitleştirilmiş örneği düşünün:


function processRequest(req, res) {
  const userId = req.userId;

  fetchData(userId, (data) => {
    transformData(userId, data, (transformedData) => {
      logData(userId, transformedData, () => {
        res.send(transformedData);
      });
    });
  });
}

Bu örnekte, userId tekrar tekrar iç içe geçmiş geri aramalar yoluyla aktarılır. Bu yaklaşım yalnızca ayrıntılı olmakla kalmaz, aynı zamanda işlevleri sıkı bir şekilde birleştirerek yeniden kullanılabilmelerini ve test edilmelerini zorlaştırır.

AsyncLocalStorage'ı Tanıtıyoruz

AsyncLocalStorage, Node.js'de belirli bir asenkron bağlama özgü verileri depolamak için bir mekanizma sağlayan yerleşik bir modüldür. Aynı yürütme bağlamındaki asenkron sınırlar arasında otomatik olarak yayılan değerleri ayarlamanıza ve almanıza olanak tanır. Bu, istek kapsamlı değişkenlerin yönetimini önemli ölçüde basitleştirir.

AsyncLocalStorage Nasıl Çalışır

AsyncLocalStorage, geçerli asenkron işlemle ilişkili bir depolama bağlamı oluşturarak çalışır. Yeni bir asenkron işlem başlatıldığında (örneğin, bir söz, bir geri çağırma), depolama bağlamı otomatik olarak yeni işleme yayılır. Bu, aynı verilerin tüm asenkron çağrı zinciri boyunca erişilebilir olmasını sağlar.

AsyncLocalStorage'ın Temel Kullanımı

İşte AsyncLocalStorage'ı nasıl kullanacağınıza dair temel bir örnek:


const { AsyncLocalStorage } = require('async_hooks');

const asyncLocalStorage = new AsyncLocalStorage();

function processRequest(req, res) {
  const userId = req.userId;

  asyncLocalStorage.run(new Map(), () => {
    asyncLocalStorage.getStore().set('userId', userId);

    fetchData().then(data => {
      return transformData(data);
    }).then(transformedData => {
      return logData(transformedData);
    }).then(() => {
      res.send(transformedData);
    });
  });
}

async function fetchData() {
  const userId = asyncLocalStorage.getStore().get('userId');
  // ... userId kullanarak veri getir
  return data;
}

async function transformData(data) {
  const userId = asyncLocalStorage.getStore().get('userId');
  // ... userId kullanarak verileri dönüştür
  return transformedData;
}

async function logData(data) {
  const userId = asyncLocalStorage.getStore().get('userId');
  // ... userId kullanarak verileri günlüğe kaydet
  return;
}

Bu örnekte:

AsyncLocalStorage için Kullanım Alanları

AsyncLocalStorage özellikle aşağıdaki senaryolarda kullanışlıdır:

1. İstek İzleme

Dağıtılmış sistemlerde, performansı izlemek ve darboğazları belirlemek için istekleri birden çok hizmette izlemek çok önemlidir. AsyncLocalStorage, hizmet sınırları arasında yayılan benzersiz bir istek kimliğini depolamak için kullanılabilir. Bu, farklı hizmetlerden gelen günlükleri ve metrikleri ilişkilendirmenize olanak tanır ve isteğin yolculuğunun kapsamlı bir görünümünü sunar. Örneğin, bir kullanıcı isteğinin bir API ağ geçidi, bir kimlik doğrulama hizmeti ve bir veri işleme hizmetinden geçtiği bir mikro hizmet mimarisini düşünün. AsyncLocalStorage kullanılarak, API ağ geçidinde benzersiz bir istek kimliği oluşturulabilir ve isteğin işlenmesine dahil olan tüm sonraki hizmetlere otomatik olarak yayılabilir.

2. Günlük Kaydı Bağlamı

Olayları günlüğe kaydederken, kullanıcı kimliği, istek kimliği veya oturum kimliği gibi bağlamsal bilgileri eklemek genellikle yararlıdır. AsyncLocalStorage, sorunları hata ayıklamayı ve analiz etmeyi kolaylaştırarak bu bilgileri otomatik olarak günlük mesajlarına eklemek için kullanılabilir. Uygulamanızdaki kullanıcı etkinliğini izlemeniz gereken bir senaryo hayal edin. Kullanıcı kimliğini AsyncLocalStorage'da depolayarak, o kullanıcının oturumuyla ilgili tüm günlük mesajlarına otomatik olarak ekleyebilir, davranışları ve karşılaşabilecekleri potansiyel sorunlar hakkında değerli bilgiler sağlayabilirsiniz.

3. Kimlik Doğrulama ve Yetkilendirme

AsyncLocalStorage, kullanıcının rolleri ve izinleri gibi kimlik doğrulama ve yetkilendirme bilgilerini depolamak için kullanılabilir. Bu, kullanıcının kimlik bilgilerini her fonksiyona açıkça iletmek zorunda kalmadan uygulamanız boyunca erişim kontrol politikalarını uygulamanıza olanak tanır. Farklı kullanıcıların farklı erişim düzeylerine (örneğin, yöneticiler, normal müşteriler) sahip olduğu bir e-ticaret uygulamasını düşünün. Kullanıcının rollerini AsyncLocalStorage'da depolayarak, belirli eylemleri gerçekleştirmelerine izin vermeden önce izinlerini kolayca kontrol edebilir, yalnızca yetkili kullanıcıların hassas verilere veya işlevlere erişebilmesini sağlayabilirsiniz.

4. Veritabanı İşlemleri

Veritabanlarıyla çalışırken, işlemleri birden çok asenkron işlem arasında yönetmek genellikle gereklidir. AsyncLocalStorage, veritabanı bağlantısını veya işlem nesnesini depolamak için kullanılabilir ve aynı istek içindeki tüm işlemlerin aynı işlem içinde yürütülmesini sağlar. Örneğin, bir kullanıcı sipariş veriyorsa, birden çok tabloyu (örneğin, siparişler, sipariş_öğeleri, envanter) güncellemeniz gerekebilir. Veritabanı işlem nesnesini AsyncLocalStorage'da depolayarak, tüm bu güncellemelerin tek bir işlem içinde gerçekleştirilmesini sağlayabilir, atomikliği ve tutarlılığı garanti edebilirsiniz.

5. Çoklu Kiracılık

Çoklu kiracılı uygulamalarda, her kiracı için verileri ve kaynakları yalıtmak çok önemlidir. AsyncLocalStorage, kiracı kimliğini depolamak için kullanılabilir ve istekleri geçerli kiracıya göre uygun veri deposuna veya kaynağa dinamik olarak yönlendirmenize olanak tanır. Birden çok kuruluşun aynı uygulama örneğini kullandığı bir SaaS platformu hayal edin. Kiracı kimliğini AsyncLocalStorage'da depolayarak, her kuruluşun verilerinin ayrı tutulmasını ve yalnızca kendi kaynaklarına erişebilmelerini sağlayabilirsiniz.

AsyncLocalStorage Kullanımı için En İyi Uygulamalar

AsyncLocalStorage güçlü bir araç olsa da, potansiyel performans sorunlarından kaçınmak ve kod netliğini korumak için dikkatli bir şekilde kullanmak önemlidir. İşte akılda tutulması gereken bazı en iyi uygulamalar:

1. Veri Depolamasını En Aza İndirin

AsyncLocalStorage'da yalnızca kesinlikle gerekli olan verileri depolayın. Büyük miktarda veri depolamak, özellikle yüksek eşzamanlılık ortamlarında performansı etkileyebilir. Örneğin, tüm kullanıcı nesnesini depolamak yerine, yalnızca kullanıcı kimliğini depolamayı ve gerektiğinde kullanıcı nesnesini bir önbellekten veya veritabanından almayı düşünün.

2. Aşırı Bağlam Değişiminden Kaçının

Sık bağlam değiştirme de performansı etkileyebilir. AsyncLocalStorage'dan değerleri ayarladığınız ve aldığınız sayıyı en aza indirin. Depolama bağlamına erişme yükünü azaltmak için sık erişilen değerleri fonksiyon içinde yerel olarak önbelleğe alın. Örneğin, bir fonksiyon içinde kullanıcı kimliğine birden çok kez erişmeniz gerekiyorsa, AsyncLocalStorage'dan bir kez alın ve sonraki kullanım için yerel bir değişkende saklayın.

3. Açık ve Tutarlı Adlandırma Kuralları Kullanın

AsyncLocalStorage'da depoladığınız anahtarlar için açık ve tutarlı adlandırma kuralları kullanın. Bu, kodun okunabilirliğini ve sürdürülebilirliğini artıracaktır. Örneğin, belirli bir özellik veya etki alanı ile ilgili tüm anahtarlar için request.id veya user.id gibi tutarlı bir önek kullanın.

4. Kullandıktan Sonra Temizleyin

AsyncLocalStorage, asenkron işlem tamamlandığında depolama bağlamını otomatik olarak temizlese de, artık ihtiyaç duyulmadığında depolama bağlamını açıkça temizlemek iyi bir uygulamadır. Bu, bellek sızıntılarını önlemeye ve performansı artırmaya yardımcı olabilir. Bağlamı açıkça temizlemek için exit yöntemini kullanarak bunu başarabilirsiniz.

5. Performans Etkilerini Göz Önünde Bulundurun

Özellikle yüksek eşzamanlılık ortamlarında AsyncLocalStorage kullanmanın performans etkilerinin farkında olun. Kodunuzun performans gereksinimlerinizi karşıladığından emin olmak için kıyaslama yapın. Bağlam yönetimiyle ilgili potansiyel darboğazları belirlemek için uygulamanızın profilini çıkarın. AsyncLocalStorage kabul edilemez performans yükü getiriyorsa, açık bağlam aktarımı gibi alternatif yaklaşımları göz önünde bulundurun.

6. Kitaplıklarda Dikkatli Kullanın

Genel kullanım için tasarlanan kitaplıklarda AsyncLocalStorage'ı doğrudan kullanmaktan kaçının. Kitaplıklar, kullanıldıkları bağlam hakkında varsayımlarda bulunmamalıdır. Bunun yerine, kullanıcıların bağlamsal bilgileri açıkça iletmeleri için seçenekler sunun. Bu, kullanıcıların uygulamalarındaki bağlamın nasıl yönetildiğini kontrol etmelerini sağlar ve potansiyel çakışmaları veya beklenmedik davranışları önler.

AsyncLocalStorage'a Alternatifler

AsyncLocalStorage kullanışlı ve güçlü bir araç olsa da, her senaryo için her zaman en iyi çözüm değildir. İşte dikkate alınması gereken bazı alternatifler:

1. Açık Bağlam Aktarımı

En basit yaklaşım, bağlamsal bilgileri fonksiyonlara argüman olarak açıkça geçirmektir. Bu yaklaşım basittir ve anlaşılması kolaydır, ancak kodun karmaşıklığı arttıkça hantal hale gelebilir. Açık bağlam aktarımı, bağlamın nispeten küçük olduğu ve kodun derinlemesine iç içe olmadığı basit senaryolar için uygundur. Ancak, daha karmaşık senaryolar için okunması ve bakımı zor olan bir koda yol açabilir.

2. Bağlam Nesneleri

Ayrı değişkenler geçirmek yerine, tüm bağlamsal bilgileri kapsayan bir bağlam nesnesi oluşturabilirsiniz. Bu, fonksiyon imzalarını basitleştirebilir ve kodu daha okunabilir hale getirebilir. Bağlam nesneleri, açık bağlam aktarımı ve AsyncLocalStorage arasında iyi bir uzlaşmadır. İlgili bağlamsal bilgileri bir araya getirmenin bir yolunu sağlayarak kodu daha düzenli ve anlaşılması kolay hale getirirler. Ancak, yine de bağlam nesnesinin her fonksiyona açıkça geçirilmesini gerektirirler.

3. Asenkron Kancalar (Tanılama için)

Node.js'nin async_hooks modülü, asenkron işlemleri izlemek için daha genel bir mekanizma sağlar. AsyncLocalStorage'dan daha karmaşık olsa da, daha fazla esneklik ve kontrol sunar. async_hooks öncelikle tanılama ve hata ayıklama amaçları için tasarlanmıştır. Asenkron işlemlerin yaşam döngüsünü izlemenize ve yürütmeleri hakkında bilgi toplamanıza olanak tanır. Ancak, potansiyel performans yükü nedeniyle genel amaçlı bağlam yönetimi için önerilmez.

4. Tanı Bağlamı (OpenTelemetry)

OpenTelemetry, izler, metrikler ve günlükler dahil olmak üzere telemetri verilerini toplamak ve dışa aktarmak için standartlaştırılmış bir API sağlar. Tanı bağlamı özellikleri, dağıtılmış sistemlerde bağlam yayılımını yönetmek için gelişmiş ve sağlam bir çözüm sunar. OpenTelemetry ile entegre olmak, farklı hizmetler ve platformlar arasında bağlam tutarlılığını sağlamak için satıcıdan bağımsız bir yol sağlar. Bu, özellikle bağlamın hizmet sınırları arasında yayılması gerektiği karmaşık mikro hizmet mimarilerinde kullanışlıdır.

Gerçek Dünya Örnekleri

AsyncLocalStorage'ın farklı senaryolarda nasıl kullanılabileceğine dair bazı gerçek dünya örneklerini inceleyelim.

1. E-ticaret Uygulaması: İstek İzleme

Bir e-ticaret uygulamasında, kullanıcı isteklerini ürün kataloğu, alışveriş sepeti ve ödeme ağ geçidi gibi birden çok hizmette izlemek için AsyncLocalStorage'ı kullanabilirsiniz. Bu, her hizmetin performansını izlemenize ve kullanıcı deneyimini etkileyebilecek darboğazları belirlemenize olanak tanır.


// API ağ geçidinde
const { AsyncLocalStorage } = require('async_hooks');
const { v4: uuidv4 } = require('uuid');

const asyncLocalStorage = new AsyncLocalStorage();

app.use((req, res, next) => {
  const requestId = uuidv4();
  asyncLocalStorage.run(new Map(), () => {
    asyncLocalStorage.getStore().set('requestId', requestId);
    res.setHeader('X-Request-Id', requestId);
    next();
  });
});

// Ürün kataloğu hizmetinde
async function getProductDetails(productId) {
  const requestId = asyncLocalStorage.getStore().get('requestId');
  // İste kimliğini diğer ayrıntılarla birlikte günlüğe kaydedin
  logger.info(`[${requestId}] ${productId} ürün kimliği için ürün ayrıntıları getiriliyor`);
  // ... ürün ayrıntılarını getir
}

2. SaaS Platformu: Çoklu Kiracılık

Bir SaaS platformunda, kiracı kimliğini depolamak ve istekleri geçerli kiracıya göre uygun veri deposuna veya kaynağa dinamik olarak yönlendirmek için AsyncLocalStorage'ı kullanabilirsiniz. Bu, her kiracının verilerinin ayrı tutulmasını ve yalnızca kendi kaynaklarına erişebilmelerini sağlar.


// İstekten kiracı kimliğini çıkarmak için ara yazılım
app.use((req, res, next) => {
  const tenantId = req.headers['x-tenant-id'];
  asyncLocalStorage.run(new Map(), () => {
    asyncLocalStorage.getStore().set('tenantId', tenantId);
    next();
  });
});

// Belirli bir kiracı için veri getirme fonksiyonu
async function fetchData(query) {
  const tenantId = asyncLocalStorage.getStore().get('tenantId');
  const db = getDatabaseConnection(tenantId);
  return db.query(query);
}

3. Mikro hizmetler Mimarisi: Günlük Kaydı Bağlamı

Bir mikro hizmetler mimarisinde, kullanıcı kimliğini depolamak ve farklı hizmetlerden gelen günlük mesajlarına otomatik olarak eklemek için AsyncLocalStorage'ı kullanabilirsiniz. Bu, belirli bir kullanıcıyı etkileyebilecek sorunlara hata ayıklamayı ve analiz etmeyi kolaylaştırır.


// Kimlik doğrulama hizmetinde
app.use((req, res, next) => {
  const userId = req.user.id;
  asyncLocalStorage.run(new Map(), () => {
    asyncLocalStorage.getStore().set('userId', userId);
    next();
  });
});

// Veri işleme hizmetinde
async function processData(data) {
  const userId = asyncLocalStorage.getStore().get('userId');
  logger.info(`[Kullanıcı Kimliği: ${userId}] Veri işleniyor: ${JSON.stringify(data)}`);
  // ... verileri işle
}

Sonuç

AsyncLocalStorage, asenkron JavaScript ortamlarında istek kapsamlı değişkenleri yönetmek için değerli bir araçtır. Asenkron işlemler arasında bağlam yönetimini basitleştirerek kodu daha okunabilir, sürdürülebilir ve güvenli hale getirir. Kullanım alanlarını, en iyi uygulamalarını ve alternatiflerini anlayarak, sağlam ve ölçeklenebilir uygulamalar oluşturmak için AsyncLocalStorage'dan etkili bir şekilde yararlanabilirsiniz. Ancak, performans etkilerini dikkatlice değerlendirmek ve potansiyel sorunlardan kaçınmak için dikkatli bir şekilde kullanmak çok önemlidir. Asenkron JavaScript geliştirme uygulamalarınızı geliştirmek için AsyncLocalStorage'ı dikkatlice benimseyin.

Açık örnekler, pratik tavsiyeler ve kapsamlı bir genel bakış sunarak, bu kılavuz dünya çapındaki geliştiricileri JavaScript uygulamalarında AsyncLocalStorage kullanarak asenkron bağlamı etkili bir şekilde yönetme bilgisiyle donatmayı amaçlamaktadır. Belirli ihtiyaçlarınız için en iyi çözümü sağlamak için performans etkilerini ve alternatifleri göz önünde bulundurmayı unutmayın.