{"id":4660,"date":"2024-11-03T21:10:20","date_gmt":"2024-11-03T20:10:20","guid":{"rendered":"https:\/\/gokhan-gokalp.com\/?p=4660"},"modified":"2024-12-10T18:38:18","modified_gmt":"2024-12-10T17:38:18","slug":"overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures","status":"publish","type":"post","link":"https:\/\/gokhan-gokalp.com\/tr\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/","title":{"rendered":"Event-Driven Architecture&#8217;larda Conditional Claim-Check Pattern&#8217;\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek"},"content":{"rendered":"<p>G\u00fcn\u00fcm\u00fcz teknoloji \u00e7a\u011f\u0131nda, geli\u015ftirdi\u011fimiz uygulama \u00e7\u00f6z\u00fcmlerini olabildi\u011fince <strong>\u00f6l\u00e7eklenebilir<\/strong>, <strong>dayan\u0131kl\u0131<\/strong> ve <strong>esnek<\/strong> hale getirebilmek i\u00e7in genellikle <strong>event-driven architecture<\/strong> temelli yap\u0131lar \u00fczerinde in\u015fa ediyoruz. Event-driven architecture her ne kadar kula\u011fa ho\u015f gelse de beraberinde bir\u00e7ok karma\u015f\u0131kl\u0131k ve <strong>limitasyonlar<\/strong> da getirmektedir. Daha \u00f6nceki makalelerim de dayan\u0131kl\u0131 ve esnek bir microservice altyap\u0131s\u0131 in\u015faa edebilmek i\u00e7in ne gibi best practice&#8217;leri uygulayabilece\u011fimiz gibi konulara da de\u011finmeye \u00e7al\u0131\u015fm\u0131\u015ft\u0131m.<\/p>\n<p>Bunlardan bir ka\u00e7\u0131;<\/p>\n<ul>\n<li><em><a href=\"https:\/\/gokhan-gokalp.com\/tr\/providing-atomicity-for-eventual-consistency-with-outbox-pattern-in-net-microservices\/\">.NET Microservice\u2019lerinde Outbox Pattern\u2019\u0131 ile Eventual Consistency i\u00e7in Atomicity Sa\u011flama<\/a><\/em><\/li>\n<li><em><a href=\"https:\/\/gokhan-gokalp.com\/tr\/how-should-my-event-be-designed-some-thoughts-on-event-based-systems\/\">Event\u2019im Nas\u0131l Olmal\u0131? Event-Based Sistemler Hakk\u0131nda Baz\u0131 D\u00fc\u015f\u00fcnceler<\/a><\/em><\/li>\n<li><em><a href=\"https:\/\/gokhan-gokalp.com\/tr\/implementation-of-choreography-based-saga-in-dotnet-microservices\/\">.NET Microservice\u2019lerinde Choreography-based Saga<\/a><\/em><\/li>\n<li><em><a href=\"https:\/\/gokhan-gokalp.com\/tr\/resiliency-patterns-in-microservice-architecture\/\" target=\"_blank\" rel=\"noopener\">Microservice Mimarisinde Resiliency Pattern\u2019lar\u0131<\/a><\/em><\/li>\n<\/ul>\n<p>Bu makalede ise, limitasyonlardan biri olan <strong>event\/message boyut limitini<\/strong> ele almaya \u00e7al\u0131\u015faca\u011f\u0131m.<\/p>\n<h1>Event Boyutunun \u00d6nemi<\/h1>\n<p>Event-driven architecture ba\u011flam\u0131nda event boyutlar\u0131n\u0131n \u00f6nemi olduk\u00e7a b\u00fcy\u00fckt\u00fcr. T\u00fcm sistem event&#8217;ler \u00fczerine kurulu oldu\u011fu i\u00e7in, bir event&#8217;in boyutu t\u00fcm sistemin <strong>\u00f6l\u00e7eklenebilirli\u011finde<\/strong>, <strong>performans\u0131nda<\/strong>\u00a0ve <strong>maliyeti<\/strong> \u00fczerinde do\u011frudan etkili olabilmektedir.<\/p>\n<p>Normal \u015fartlar alt\u0131nda genellikle event payload boyutlar\u0131n\u0131n kolay kolay \u00e7ok fazla b\u00fcy\u00fck olaca\u011f\u0131n\u0131 d\u00fc\u015f\u00fcnm\u00fcyorum. Ama bazen farkl\u0131 gereksinimleri gerektiren domain&#8217;ler \u00fczerinde \u00e7al\u0131\u015f\u0131yor olabiliriz.<\/p>\n<p>\u00d6rne\u011fin, e-ticaret domaininde sipari\u015f servisi taraf\u0131ndan bir sipari\u015f olu\u015fturuldu\u011funda fatura servisi ilgili event&#8217;i dinleyerek <em>PDF<\/em> format\u0131nda bir fatura olu\u015fturabilir. Bu <em>PDF<\/em> faturan\u0131n ise farkl\u0131 servisler taraf\u0131ndan kullan\u0131lmas\u0131 gerekebilir. \u00d6rne\u011fin ba\u015fka bir servis taraf\u0131ndan kullan\u0131c\u0131ya ilgili fatura g\u00f6nderilebilir veya yine ba\u015fka bir servis taraf\u0131ndan ilgili fatura uzun s\u00fcreli saklama i\u00e7in ar\u015five kaydedilebilir.<\/p>\n<p>Veya <em><a href=\"https:\/\/gokhan-gokalp.com\/tr\/how-should-my-event-be-designed-some-thoughts-on-event-based-systems\/\">fat events<\/a><\/em> yakla\u015f\u0131m\u0131n\u0131 kullan\u0131yor olabiliriz. Bu yakla\u015f\u0131mda, ilgili domain\u2019in \u00e7ok fazla attribute\u2019e sahip olmas\u0131 nedeniyle event payload\u2019lar\u0131 olduk\u00e7a b\u00fcy\u00fck olabilir.<\/p>\n<p>K\u0131sacas\u0131, bu gibi senaryolarda bazen event boyutlar\u0131 domain&#8217;lere g\u00f6re farkl\u0131l\u0131k g\u00f6sterebilmekte ve bu event&#8217;leri farkl\u0131 domain&#8217;ler aras\u0131nda payla\u015fabilmekteyiz. Elbette bu kararlar\u0131 vermeden \u00f6nce, bunlar\u0131n genel sistem \u00fczerindeki etkilerini de iyi anlamam\u0131z gerekmektedir. Mesela baz\u0131 durumlarda genel performansa olaca\u011f\u0131 minimal etkileri kabul edebilsek de, maliyeti artt\u0131rabilece\u011fi durumlarda farkl\u0131 \u00e7\u00f6z\u00fcmler uygulamam\u0131z gerekebilmektedir.<\/p>\n<p>\u00d6rne\u011fin, <em>Azure Service Bus<\/em> gibi fully managed bir message broker kullan\u0131yor olabiliriz. <em>Azure Service Bus<\/em>, standard tier&#8217;\u0131 i\u00e7erisinde bizlere 256KB&#8217;l\u0131k bir message boyut s\u0131n\u0131rlamas\u0131 getirmektedir. Elbette bu s\u0131n\u0131rlamay\u0131 100MB&#8217;a kadar premium tier&#8217;\u0131 ile artt\u0131rabilmekteyiz. Ancak s\u00f6z konusu maliyet-fayda oran\u0131n\u0131 maksimize etmek oldu\u011funda, maliyetleri \u00e7ok fazla artt\u0131rmadan, best practice&#8217;lerle bu tarz problemleri nas\u0131l \u00e7\u00f6zebilece\u011fimize odaklanmam\u0131z bizlere daha faydal\u0131 olacakt\u0131r.<\/p>\n<h1>Claim-Check Pattern&#8217;\u0131<\/h1>\n<p>Claim-check pattern&#8217;\u0131 ise bahsetmi\u015f oldu\u011fumuz senaryolar kar\u015f\u0131s\u0131nda kullanabilece\u011fimiz bir <strong>messaging<\/strong> pattern&#8217;\u0131d\u0131r.<\/p>\n<p>Bu pattern, b\u00fcy\u00fck boyutlu event payload&#8217;lar\u0131n\u0131n message broker&#8217;lar \u00fczerinden ta\u015f\u0131nmas\u0131 yerine, ilgili payload verisinin external bir storage \u00fczerinde saklanmas\u0131n\u0131 ve buna referans eden bir token veya key&#8217;in (claim-check) olu\u015fturulmas\u0131n\u0131 \u00f6nermektedir. \u0130lgili event consumer&#8217;lar\u0131n\u0131n ise, olu\u015fturulan referans\u0131 kullanarak ilgili veriyi storage \u00fczerinden elde edebileceklerini s\u00f6ylemektedir. Bu sayede hem messaging sisteminin performans\u0131 optimize edebilmemize olanak tan\u0131rken, hem de olu\u015fabilecek potansiyel maliyetleri de alternatif bir y\u00f6ntemle kontrol alt\u0131na alabilmemizi sa\u011flamaktad\u0131r.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2024\/11\/claim-check-pattern.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4667 lazyload\" data-src=\"\/wp-content\/uploads\/2024\/11\/claim-check-pattern.jpg\" alt=\"\" width=\"821\" height=\"322\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/claim-check-pattern.jpg 821w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/claim-check-pattern-300x118.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/claim-check-pattern-768x301.jpg 768w\" data-sizes=\"(max-width: 821px) 100vw, 821px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 821px; --smush-placeholder-aspect-ratio: 821\/322;\" \/><\/a><\/p>\n<h1>Implemente Edelim<\/h1>\n<p>Microservice&#8217;lerimiz i\u00e7inde, claim-check pattern&#8217;\u0131n\u0131 <strong>ko\u015fullu<\/strong> bir \u015fekilde kolayca nas\u0131l implemente edebilece\u011fimize bir bakal\u0131m.<\/p>\n<p data-pm-slice=\"0 0 []\">\u00d6rnek senaryo olarak bir e-ticaret domain&#8217;i i\u00e7erisinde \u00e7al\u0131\u015ft\u0131\u011f\u0131m\u0131z\u0131 d\u00fc\u015f\u00fcnelim ve sistem i\u00e7erisinde bir sipari\u015f olu\u015fturulduktan sonra b\u00fcy\u00fck bir &#8220;<code>OrderCreatedEvent<\/code>&#8221; publish edildi\u011fini varsayal\u0131m. Bu \u00f6rne\u011fimizde, message broker olarak <em>Azure Service Bus <\/em>&#8216;\u0131, external storage olarak ise <em>Azure Storage Account<\/em> &#8216;u kullanaca\u011f\u0131m. \u015eimdi, i\u015fe servislerimiz aras\u0131nda messaging i\u015flemlerini ger\u00e7ekle\u015ftirecek basit bir service bus k\u00fct\u00fcphanesi geli\u015ftirerek ba\u015flayal\u0131m.<\/p>\n<p data-pm-slice=\"0 0 []\">\u0130lk olarak &#8220;<code>TodoEcom.ServiceBus<\/code>&#8221; ad\u0131nda bir <em>.NET 9<\/em> class library projesi olu\u015ftural\u0131m ve ard\u0131ndan i\u00e7erisine a\u015fa\u011f\u0131daki <em>NuGet<\/em> package&#8217;lar\u0131n\u0131 dahil edelim.<\/p>\n<div>\n<ul>\n<li>Azure.Messaging.ServiceBus<\/li>\n<li>Azure.Storage.Blobs<\/li>\n<li>Microsoft.Extensions.Configuration.Binder<\/li>\n<li>Microsoft.Extensions.Http<\/li>\n<li>System.Configuration.ConfigurationManager<\/li>\n<\/ul>\n<div>Ard\u0131ndan &#8220;<code>ServiceBus<\/code>&#8221; ad\u0131nda bir class olu\u015fturarak i\u00e7erisinde ilk olarak &#8220;<code>IServiceBus<\/code>&#8221; interface&#8217;ini ve <em>Azure Service Bus<\/em> message&#8217;lar\u0131n\u0131 customize edece\u011fimiz wrapper&#8217;\u0131 tan\u0131mlayal\u0131m.<\/div>\n<\/div>\n<pre>using System.Collections.Concurrent;\r\nusing System.Text.Json;\r\nusing Azure.Messaging.ServiceBus;\r\nusing Azure.Storage.Blobs;\r\nusing Microsoft.Extensions.Configuration;\r\n\r\nnamespace TodoEcom.ServiceBus;\r\n\r\npublic interface IServiceBus\r\n{\r\n    Task Publish&lt;T&gt;(T @event, string? queueName = null, CancellationToken cancellationToken = default);\r\n    Task Receive&lt;ServiceBusReceivedMessageWrapper&lt;T&gt;&gt;(string? queueName = null, CancellationToken cancellationToken = default);\r\n}\r\n\r\npublic class ServiceBusReceivedMessageWrapper&lt;T&gt;\r\n{\r\n    private readonly ServiceBusReceivedMessage _receivedMessage;\r\n    private readonly ServiceBusReceiver _receiver;\r\n    public T Data { get; }\r\n\r\n    internal ServiceBusReceivedMessageWrapper(ServiceBusReceivedMessage receivedMessage, ServiceBusReceiver receiver, T payload)\r\n    {\r\n        _receivedMessage = receivedMessage;\r\n        _receiver = receiver;\r\n        Data = payload;\r\n    }\r\n\r\n    public async Task CompleteAsync()\r\n    {\r\n        await _receiver.CompleteMessageAsync(_receivedMessage);\r\n    }\r\n}<\/pre>\n<div>\n<p data-pm-slice=\"1 1 []\">Bu noktada, event&#8217;leri basit bir \u015fekilde publish edip consume edebilece\u011fimiz bir interface tan\u0131ml\u0131yoruz. Bu service bus library&#8217;si i\u00e7erisinde conditional bir \u015fekilde claim-check pattern&#8217;\u0131n\u0131 implemente edece\u011fimiz i\u00e7in, <em>Azure Service Bus<\/em> client library&#8217;sinin kullanmakta oldu\u011fu &#8220;<code>ServiceBusReceivedMessage<\/code>&#8221; class&#8217;\u0131n\u0131 encapsulate ederek kendi &#8220;<code>ServiceBusReceivedMessageWrapper<\/code>&#8221; class&#8217;\u0131m\u0131z\u0131 olu\u015fturuyoruz. Bu tasar\u0131m, ilgili event&#8217;in payload&#8217;unun boyutuna g\u00f6re, payload&#8217;un tutulaca\u011f\u0131 &#8220;<code>Data<\/code>&#8221; property&#8217;sini ya <em>Azure Storage Account<\/em> \u00fczerinden ya da do\u011frudan <em>Azure Service Bus <\/em>\u00fczerinden elde ederek haz\u0131rlayabilmemizi m\u00fcmk\u00fcn k\u0131l\u0131yor olacak. B\u00f6ylece, bu library&#8217;yi kullanan servisler, altyap\u0131da ger\u00e7ekle\u015fen i\u015flemlerden ba\u011f\u0131ms\u0131z bir \u015fekilde event&#8217;lerini kusursuz bir \u015fekilde consume etmeye devam ediyor olabilecekler.<\/p>\n<p data-pm-slice=\"1 1 []\">Ayr\u0131ca, <em>Azure Service Bus<\/em> client library&#8217;si, consume edilen event&#8217;in tamamlanmas\u0131 i\u015flemini ger\u00e7ekle\u015ftirebilmek i\u00e7in kendi message tipi olan &#8220;<code>ServiceBusReceivedMessage<\/code>&#8221; objesine ihtiya\u00e7 duymaktad\u0131r. Bu nedenle, &#8220;<code>ServiceBusReceivedMessage<\/code>&#8221; objesini de wrapper i\u00e7erisinde encapsulate ediyor ve tamamlanma i\u015fleminin de consumer&#8217;lar taraf\u0131nda tutarl\u0131 bir \u015fekilde ger\u00e7ekle\u015ftirilebilmesi i\u00e7in &#8220;<code>CompleteAsync<\/code>&#8221; metodu ile d\u0131\u015far\u0131ya a\u00e7\u0131yor olaca\u011f\u0131z.<\/p>\n<p data-pm-slice=\"1 1 []\">\u015eimdi yine ayn\u0131 class i\u00e7erisinde &#8220;<code>IServiceBus<\/code>&#8221; interface&#8217;inin implementasyonunu \u00f6ncelikle &#8220;<code>Publish<\/code>&#8221; method&#8217;undan ba\u015flayarak par\u00e7a par\u00e7a ele alal\u0131m.<\/p>\n<pre data-pm-slice=\"1 1 []\">public class AzureServiceBus : IServiceBus\r\n{\r\n    private readonly ServiceBusClient _serviceBusClient;\r\n    private readonly BlobContainerClient? _blobContainerClient;\r\n    private readonly IHttpClientFactory _httpClientFactory;\r\n    private readonly ConcurrentDictionary&lt;string, ServiceBusSender&gt; _senderPool;\r\n    private readonly ConcurrentDictionary&lt;string, ServiceBusReceiver&gt; _receiverPool;\r\n    private readonly int _maxEventPayloadSizeLimitInKB;\r\n    private readonly int _claimCheckTokenExpirationInHours;\r\n    private const string IsClaimCheckProperty = \"IsClaimCheck\";\r\n    private const string ClaimCheckBlobUriProperty = \"ClaimCheckBlobUri\";\r\n    private readonly bool _enableClaimCheck;\r\n    private readonly string? _defaultQueueName;\r\n\r\n    public AzureServiceBus(IConfiguration configuration, IHttpClientFactory httpClientFactory)\r\n    {\r\n        var serviceBusConnectionString = configuration.GetValue&lt;string&gt;(\"ServiceBus:ConnectionString\") ?? throw new KeyNotFoundException(\"ServiceBus:ConnectionString is not found.\");\r\n        _defaultQueueName = configuration.GetValue&lt;string&gt;(\"ServiceBus:DefaultQueueName\");\r\n        _serviceBusClient = new ServiceBusClient(serviceBusConnectionString);\r\n\r\n        _httpClientFactory = httpClientFactory;\r\n\r\n        _senderPool = new ConcurrentDictionary&lt;string, ServiceBusSender&gt;();\r\n        _receiverPool = new ConcurrentDictionary&lt;string, ServiceBusReceiver&gt;();\r\n\r\n\r\n        _enableClaimCheck = configuration.GetValue&lt;bool&gt;(\"ServiceBus:ClaimCheck:EnableClaimCheck\");\r\n\r\n        if(_enableClaimCheck)\r\n        {\r\n            var blobStorageConnectionString = configuration.GetValue&lt;string&gt;(\"ServiceBus:ClaimCheck:BlobStorage:ConnectionString\") ?? throw new KeyNotFoundException(\"ServiceBus:BlobStorage:ConnectionString is not found.\");\r\n\r\n            var claimCheckContainerName = configuration.GetValue&lt;string&gt;(\"ServiceBus:ClaimCheck:BlobStorage:ClaimCheckContainerName\") ?? throw new KeyNotFoundException(\"ServiceBus:BlobStorage:ClaimCheckContainerName is not found.\");\r\n\r\n            _maxEventPayloadSizeLimitInKB = configuration.GetValue&lt;int?&gt;(\"ServiceBus:ClaimCheck:MaxEventPayloadSizeLimitInKB\") ?? throw new KeyNotFoundException(\"ServiceBus:MaxEventPayloadSizeLimitInKB is not found.\");\r\n\r\n            _claimCheckTokenExpirationInHours = configuration.GetValue&lt;int?&gt;(\"ServiceBus:ClaimCheck:BlobStorage:ClaimCheckTokenExpirationInHours\") ?? throw new KeyNotFoundException(\"ServiceBus:BlobStorage:ClaimCheckTokenExpirationInHours is not found.\");\r\n\r\n            _blobContainerClient = new BlobContainerClient(blobStorageConnectionString, claimCheckContainerName);\r\n        }\r\n    }\r\n\r\n    public async Task Publish&lt;T&gt;(T @event, string? queueName = null, CancellationToken cancellationToken = default)\r\n    {\r\n        if(string.IsNullOrEmpty(queueName))\r\n        {\r\n            queueName = _defaultQueueName!;\r\n        }\r\n\r\n        var sender = _senderPool.GetOrAdd(queueName, _serviceBusClient.CreateSender);\r\n\r\n        var serializedEvent = JsonSerializer.SerializeToUtf8Bytes(@event);\r\n\r\n        ServiceBusMessage message;\r\n        if (_enableClaimCheck &amp;&amp; IsEventPayloadSizeExceedsLimit(serializedEvent))\r\n        {\r\n            var blobUri = await UploadPayloadToBlobAsync(serializedEvent, queueName, @event!.GetType().Name);\r\n\r\n            message = new ServiceBusMessage\r\n            {\r\n                ApplicationProperties =\r\n                {\r\n                    [IsClaimCheckProperty] = true,\r\n                    [ClaimCheckBlobUriProperty] = blobUri\r\n                }\r\n            };\r\n        }\r\n        else\r\n        {\r\n            message = new ServiceBusMessage(serializedEvent);\r\n        }\r\n\r\n        await sender.SendMessageAsync(message, cancellationToken);\r\n    }\r\n\r\n    private bool IsEventPayloadSizeExceedsLimit(byte[] serializedEvent)\r\n    {\r\n        var eventSize = serializedEvent.Length;\r\n        Console.WriteLine(eventSize);\r\n        return eventSize &gt; _maxEventPayloadSizeLimitInKB * 1024;\r\n    }\r\n\r\n    private async Task&lt;string&gt; UploadPayloadToBlobAsync(byte[] serializedEvent, string queueName, string eventType)\r\n    {\r\n        var blobName = $\"{queueName}\/{eventType}\/{Guid.NewGuid()}.json\";\r\n\r\n        await _blobContainerClient!.CreateIfNotExistsAsync();\r\n        var blobClient = _blobContainerClient!.GetBlobClient(blobName);\r\n\r\n        using var stream = new MemoryStream(serializedEvent);\r\n        await blobClient.UploadAsync(stream, overwrite: true);\r\n\r\n        var sasUri = blobClient.GenerateSasUri(Azure.Storage.Sas.BlobSasPermissions.Read, DateTimeOffset.UtcNow.AddHours(_claimCheckTokenExpirationInHours));\r\n\r\n        return sasUri.ToString();\r\n    }\r\n}<\/pre>\n<p>\u00d6ncelikle, ihtiya\u00e7 duydu\u011fumuz gerekli t\u00fcm konfig\u00fcrasyon ve gerekli t\u00fcm servis injection i\u015flemlerini ger\u00e7ekle\u015ftiriyoruz. Claim-check kullan\u0131m\u0131yla ilgili karar\u0131 consumer&#8217;lara b\u0131rakabilmek i\u00e7in ise, bu \u00f6zelli\u011fin kontrol\u00fcn\u00fc &#8220;<code>ServiceBus:ClaimCheck:EnableClaimCheck<\/code>&#8221; parametresine ba\u011fl\u0131yoruz. Ayr\u0131ca &#8220;<code>ServiceBusSender<\/code>&#8221; ve &#8220;<code>ServiceBusReceiver<\/code>&#8221; objelerini daha verimli y\u00f6netebilmek ad\u0131na bir pooling mekanizmas\u0131 tan\u0131ml\u0131yoruz.<\/p>\n<p>&#8220;<code>Publish<\/code>&#8221; method&#8217;u ise as\u0131l claim-check mekanizmas\u0131n\u0131 conditional olarak implemente etti\u011fimiz ana nokta. Bu noktada, ilgili event ilk olarak serialize edilmektedir ve daha sonra, &#8220;<code>IsEventPayloadSizeExceedsLimit<\/code>&#8221; blo\u011fu i\u00e7erisinde conditional olarak claim-check i\u015flemi ger\u00e7ekle\u015ftirilmektedir.\u00a0E\u011fer ilgili event&#8217;in boyutu belirlenmi\u015f s\u0131n\u0131r\u0131n \u00fczerinde ise, claim-check i\u015flemi otomatik olarak <em>Azure Blob Storage<\/em> \u00fczerinden ger\u00e7ekle\u015ftirilecektir.<\/p>\n<p>Bu noktada s\u0131ras\u0131yla:<\/p>\n<ul>\n<li>&#8220;<code>UploadPayloadToBlobAsync<\/code>&#8221; methud&#8217;u i\u00e7erisinde ilgili event payload&#8217;unu <em>Azure Blob Storage<\/em> \u00fczerine upload etme i\u015flemini ele al\u0131yoruz.<\/li>\n<li>Ard\u0131ndan ilgili payload&#8217;un <em>Azure Blob Storage<\/em> \u00fczerinden tekrar elde edilebilmesi i\u00e7in ise bir <em>SAS URI<\/em> olu\u015fturuyoruz.<\/li>\n<li>Daha sonra ise olu\u015fturmu\u015f oldu\u011fumuz bu <em>SAS URI<\/em> bilgisini, ilgili event&#8217;in metadata bilgileri i\u00e7erisine &#8220;<code>ApplicationProperties<\/code>&#8221; dahil ediyoruz.<\/li>\n<\/ul>\n<p>\u015eimdi ise &#8220;<code>Receive<\/code>&#8221; method&#8217;u ile devam edelim.<\/p>\n<pre>public class AzureServiceBus : IServiceBus\r\n{\r\n    \/\/ other codes...\r\n\r\n    public async Task&lt;ServiceBusMessageReceivedMessageWrapper&lt;T&gt;&gt; Receive&lt;T&gt;(string? queueName = null, CancellationToken cancellationToken = default)\r\n    {\r\n        if (string.IsNullOrEmpty(queueName))\r\n        {\r\n            queueName = _defaultQueueName!;\r\n        }\r\n\r\n        var receiver = _receiverPool.GetOrAdd(queueName, _serviceBusClient.CreateReceiver);\r\n\r\n        var message = await receiver.ReceiveMessageAsync(cancellationToken: cancellationToken);\r\n\r\n        ServiceBusReceivedMessageWrapper&lt;T&gt; wrappedMessage;\r\n\r\n        if (message.ApplicationProperties.TryGetValue(IsClaimCheckProperty, out var isClaimCheck) &amp;&amp; (bool)isClaimCheck)\r\n        {\r\n            var blobUri = message.ApplicationProperties[ClaimCheckBlobUriProperty] as string\r\n                  ?? throw new InvalidOperationException($\"The claim-check value is not found. Message CorrelationId: {message.CorrelationId}\");\r\n\r\n            byte[] payload = await DownloadPayloadFromBlobAsync((string)blobUri);\r\n\r\n            var actualEvent = JsonSerializer.Deserialize&lt;T&gt;(payload);\r\n\r\n            wrappedMessage = new ServiceBusReceivedMessageWrapper&lt;T&gt;(message, receiver, actualEvent!);\r\n        }\r\n        else\r\n        {\r\n            wrappedMessage = new ServiceBusReceivedMessageWrapper&lt;T&gt;(message, receiver, message.Body.ToObjectFromJson()!);\r\n        }\r\n\r\n        return wrappedMessage;\r\n    }\r\n\r\n    private async Task&lt;byte[]&gt; DownloadPayloadFromBlobAsync(string blobUri)\r\n    {\r\n        var httpClient = _httpClientFactory.CreateClient();\r\n        using var response = await httpClient.GetAsync(blobUri);\r\n\r\n        if (response.IsSuccessStatusCode)\r\n        {\r\n            return await response.Content.ReadAsByteArrayAsync();\r\n        }\r\n\r\n        throw new Exception($\"Failed to download the claim-check payload from {blobUri}. Status Code: {response.StatusCode}\");\r\n    }\r\n}<\/pre>\n<p data-pm-slice=\"0 0 []\">Bu noktada, ilgili event&#8217;i consume ettikten sonra metadata bilgileri i\u00e7erisinde claim-check token&#8217;\u0131n\u0131n yer al\u0131p almad\u0131\u011f\u0131n\u0131 kontrol ediyoruz. E\u011fer claim-check token&#8217;\u0131 mevcutsa, metadata bilgileri i\u00e7erisinden <em>Blob SAS URI<\/em> bilgisini elde ediyor ve &#8220;<code>DownloadPayloadFromBlobAsync<\/code>&#8221; method&#8217;unu kullanarak ilgili event payload&#8217;unu elde ediyoruz. Claim-check token&#8217;\u0131 bulunmuyor ise, ilgili event&#8217;i consume etti\u011fimiz gibi wrapper arac\u0131l\u0131\u011f\u0131yla ilgili consumer&#8217;a iletiyoruz. B\u00f6ylece, daha \u00f6nce de bahsetti\u011fimiz gibi, consumer&#8217;lar altyap\u0131da ger\u00e7ekle\u015fen claim-check i\u015flemlerinden ba\u011f\u0131ms\u0131z bir \u015fekilde event&#8217;leri consume etmeye devam edecektir.<\/p>\n<p data-pm-slice=\"0 0 []\">\u015eimdi, h\u0131zl\u0131ca bir test i\u015flemi ger\u00e7ekle\u015ftirebilmek i\u00e7in &#8220;<code>OrderCreatedEvent<\/code>&#8221; &#8216;ini publish edecek olan publisher&#8217;\u0131 implemente edelim. \u0130lk olarak, &#8220;<code>TodoEcom.Contracts<\/code>&#8221; ad\u0131nda bir class library olu\u015ftural\u0131m ve i\u00e7erisinde publisher ve consumer aras\u0131nda payla\u015facak oldu\u011fumuz &#8220;<code>OrderCreatedEvent<\/code>&#8221; ini a\u015fa\u011f\u0131daki gibi tan\u0131mlayal\u0131m.<\/p>\n<pre data-pm-slice=\"0 0 []\">namespace TodoEcom.Contracts.Events;\r\n\r\npublic class OrderCreatedEvent\r\n{\r\n    public int OrderId { get; set; }\r\n    public int CustomerId { get; set; }\r\n    public required string PaymentMethod { get; set; }\r\n    public DateTime CreatedAt { get; set; }\r\n    public required IReadOnlyList&lt;ProductDTO&gt; Products { get; set; }\r\n\r\n    \/\/ other attributes such as address, applied discounts, shipping details, transaction details and etc.\r\n}\r\n\r\npublic class ProductDTO\r\n{\r\n    public int ProductId { get; set; }\r\n    public required string Name { get; set; }\r\n    public int Quantity { get; set; }\r\n    public decimal Price { get; set; }\r\n}<\/pre>\n<p data-pm-slice=\"0 0 []\">Bu noktada, \u00f6rne\u011fi basit tutmak ad\u0131na \u00e7ok fazla attribute eklemedim. Ancak ana fikri iletebildi\u011fimi d\u00fc\u015f\u00fcn\u00fcyorum.<\/p>\n<p data-pm-slice=\"0 0 []\">\u015eimdi ise &#8220;<code>TodoEcom.OrderService.API<\/code>&#8221; ad\u0131nda bir <em>.NET 9<\/em> webapi projesi olu\u015ftural\u0131m ve &#8220;<code>TodoEcom.Contracts<\/code>&#8221; ile &#8220;<code>TodoEcom.ServiceBus<\/code>&#8221; library&#8217;lerini referans olarak dahil edelim. Ard\u0131ndan &#8220;<code>Program.cs<\/code>&#8221; class&#8217;\u0131n\u0131 a\u015fa\u011f\u0131daki gibi g\u00fcncelleyelim.<\/p>\n<pre data-pm-slice=\"0 0 []\">using TodoEcom.Contracts.Events;\r\nusing TodoEcom.ServiceBus;\r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nbuilder.Services.AddOpenApi();\r\nbuilder.Services.AddHttpClient();\r\nbuilder.Services.AddSingleton&lt;IServiceBus, AzureServiceBus&gt;();\r\n\r\nvar app = builder.Build();\r\n\r\nif (app.Environment.IsDevelopment())\r\n{\r\n    app.MapOpenApi();\r\n}\r\n\r\napp.UseHttpsRedirection();\r\n\r\napp.MapPost(\"\/orders\", async (IServiceBus serviceBus) =&gt;\r\n{\r\n    \/\/ Perform order operations...\r\n\r\n    var orderCreatedEvent = new OrderCreatedEvent\r\n    {\r\n        OrderId = 1,\r\n        CustomerId = 123,\r\n        PaymentMethod = \"CreditCard\",\r\n        CreatedAt = DateTime.UtcNow,\r\n        Products = Enumerable.Range(1,20).Select(i =&gt; new ProductDTO\r\n        {\r\n            ProductId = i,\r\n            Name = $\"My product {i}\",\r\n            Quantity = 1,\r\n            Price = i,\r\n        }).ToList()\r\n    };\r\n\r\n    await serviceBus.Publish(orderCreatedEvent);\r\n\r\n})\r\n.WithName(\"CreateAnOrder\");\r\n\r\napp.Run();<\/pre>\n<p>Bu noktada, gerekli client&#8217;lar\u0131n registration i\u015flemlerini ger\u00e7ekle\u015ftirdikten sonra implemente etmi\u015f oldu\u011fumuz service bus library&#8217;sini kullanarak \u00f6rnek bir &#8220;<code>OrderCreatedEvent<\/code>&#8221; &#8216;i publish ediyoruz. Claim-check mekanizmas\u0131n\u0131 test edebilmek i\u00e7in ise, publish edecek oldu\u011fumuz bu event&#8217;in belirleyecek oldu\u011fumuz payload limitini a\u015fabilmesi ad\u0131na i\u00e7erisine birka\u00e7 \u00fcr\u00fcn bilgisi ekliyoruz.<\/p>\n<p>\u015eimdi &#8220;<code>appsettings.json<\/code>&#8221; dosyas\u0131n\u0131 ise a\u015fa\u011f\u0131daki gibi g\u00fcncelleyelim.<\/p>\n<pre>{\r\n  \"Logging\": {\r\n    \"LogLevel\": {\r\n      \"Default\": \"Information\",\r\n      \"Microsoft.AspNetCore\": \"Warning\"\r\n    }\r\n  },\r\n  \"AllowedHosts\": \"*\",\r\n  \"ServiceBus\": {\r\n    \"ConnectionString\": \"Endpoint=sb:\/\/mypocsbus.servicebus.windows.net\/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=YOUR_SHARED_ACCESS_KEY\",\r\n    \"DefaultQueueName\": \"orders\",\r\n    \"ClaimCheck\": {\r\n      \"EnableClaimCheck\": true,\r\n      \"MaxEventPayloadSizeLimitInKB\": 1,\r\n      \"BlobStorage\": {\r\n        \"ConnectionString\": \"DefaultEndpointsProtocol=https;AccountName=mypocstorageac;AccountKey=YOUR_ACCOUNT_KEY;EndpointSuffix=core.windows.net\",\r\n        \"ClaimCheckContainerName\": \"claim-check\",\r\n        \"ClaimCheckTokenExpirationInHours\": 1\r\n      }\r\n    }\r\n  }\r\n}<\/pre>\n<p data-pm-slice=\"0 0 []\">Bu noktada, &#8220;<code>EnableClaimCheck<\/code>&#8221; parametresi ile claim-check \u00f6zelli\u011fini kullanaca\u011f\u0131m\u0131z\u0131 belirtiyor, &#8220;<code>MaxEventPayloadSizeLimitInKB<\/code>&#8221; parametresi ile ise <em>Azure Service Bus<\/em> \u00fczerine publish etmek istedi\u011fimiz event boyutunu <strong>1<\/strong> KB ile s\u0131n\u0131rl\u0131yoruz.<\/p>\n<p data-pm-slice=\"0 0 []\">\u015eimdi, &#8220;<code>TodoEcom.BillingService.Consumer<\/code>&#8221; ad\u0131nda bir <em>.NET 9<\/em> worker projesi olu\u015ftural\u0131m ve &#8220;<code>TodoEcom.Contracts<\/code>&#8221; ile &#8220;<code>TodoEcom.ServiceBus<\/code>&#8221; library&#8217;lerini referans olarak ekleyelim. Ard\u0131ndan, &#8220;<code>OrderCreatedEvent<\/code>&#8221; &#8216;inin consume i\u015flemini ger\u00e7ekle\u015ftirelim.<\/p>\n<pre data-pm-slice=\"0 0 []\">using TodoEcom.Contracts.Events;\r\nusing TodoEcom.ServiceBus;\r\n\r\nnamespace TodoEcom.BillingService.Consumer;\r\n\r\npublic class Worker : BackgroundService\r\n{\r\n    private readonly ILogger&lt;Worker&gt; _logger;\r\n    private readonly IServiceBus _serviceBus;\r\n    private const string OrdersQueueName = \"orders\";\r\n\r\n    public Worker(ILogger&lt;Worker&gt; logger, IServiceBus serviceBus)\r\n    {\r\n        _logger = logger;\r\n        _serviceBus = serviceBus;\r\n    }\r\n\r\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\r\n    {\r\n        while (!stoppingToken.IsCancellationRequested)\r\n        {\r\n            if (_logger.IsEnabled(LogLevel.Information))\r\n            {\r\n                _logger.LogInformation(\"Worker running at: {time}\", DateTimeOffset.Now);\r\n            }\r\n\r\n            var @event = await _serviceBus.Receive&lt;OrderCreatedEvent&gt;(OrdersQueueName, stoppingToken);\r\n\r\n            Console.WriteLine($\"Event received. OrderId: {@event.Data.OrderId} \");\r\n\r\n            \/\/ some operations...\r\n\r\n            await @event.CompleteAsync();\r\n        }\r\n    }\r\n}<\/pre>\n<p>&#8220;<code>appsettings.json<\/code>&#8221; dosyas\u0131n\u0131 da a\u015fa\u011f\u0131daki gibi g\u00fcncelleyelim.<\/p>\n<pre>{\r\n  \"Logging\": {\r\n    \"LogLevel\": {\r\n      \"Default\": \"Information\",\r\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\r\n    }\r\n  },\r\n  \"ServiceBus\": {\r\n    \"ConnectionString\": \"Endpoint=sb:\/\/mypocsbus.servicebus.windows.net\/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=YOUR_SHARED_ACCESS_KEY\"\r\n  }\r\n}<\/pre>\n<p>Art\u0131k test etmeye haz\u0131r\u0131z.<\/p>\n<h1>Test Edelim<\/h1>\n<p>\u0130lk olarak &#8220;<code>TodoEcom.OrderService.API<\/code>&#8221; projesini \u00e7al\u0131\u015ft\u0131ral\u0131m ve &#8220;<code>\/orders<\/code>&#8221; endpoint&#8217;ini trigger edelim.<\/p>\n<pre>curl -X POST http:\/\/localhost:5065\/orders<\/pre>\n<p>Ard\u0131ndan, <em>Azure Portal<\/em> \u00fczerinden &#8220;<code>Service Bus Explorer<\/code>&#8221; &#8216;\u0131 kullanarak, &#8220;<code>orders<\/code>&#8221; queue&#8217;suna publish etmi\u015f oldu\u011fumuz message&#8217;\u0131n &#8220;<code>Custom Properties<\/code>&#8221; b\u00f6l\u00fcm\u00fcne bir bakal\u0131m.<\/p>\n<figure id=\"attachment_4679\" aria-describedby=\"caption-attachment-4679\" style=\"width: 2326px\" class=\"wp-caption aligncenter\"><a href=\"\/wp-content\/uploads\/2024\/11\/service-bus-queue.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4679 lazyload\" data-src=\"\/wp-content\/uploads\/2024\/11\/service-bus-queue.jpg\" alt=\"\" width=\"2326\" height=\"1800\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/service-bus-queue.jpg 2326w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/service-bus-queue-300x232.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/service-bus-queue-1024x792.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/service-bus-queue-768x594.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/service-bus-queue-1536x1189.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/service-bus-queue-2048x1585.jpg 2048w\" data-sizes=\"(max-width: 2326px) 100vw, 2326px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2326px; --smush-placeholder-aspect-ratio: 2326\/1800;\" \/><\/a><figcaption id=\"caption-attachment-4679\" class=\"wp-caption-text\">Service Bus Queue<\/figcaption><\/figure>\n<p>Bu noktada, publish etti\u011fimiz event payload&#8217;unun <em>Azure Blob Storage<\/em> &#8216;a y\u00fcklenip, ilgili <em>Blob SAS URI <\/em>bilgisinin &#8220;<code>ClaimCheckBlobUri<\/code>&#8221; property&#8217;sine eklendi\u011fini g\u00f6rebiliriz.<\/p>\n<p>Ard\u0131ndan &#8220;<code>TodoEcom.BillingService.Consumer<\/code>&#8221; projesini \u00e7al\u0131\u015ft\u0131ral\u0131m ve ilgili event&#8217;i consume edelim.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2024\/11\/receive-event.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4681 lazyload\" data-src=\"\/wp-content\/uploads\/2024\/11\/receive-event.jpg\" alt=\"\" width=\"2504\" height=\"406\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/receive-event.jpg 2504w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/receive-event-300x49.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/receive-event-1024x166.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/receive-event-768x125.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/receive-event-1536x249.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/receive-event-2048x332.jpg 2048w\" data-sizes=\"(max-width: 2504px) 100vw, 2504px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2504px; --smush-placeholder-aspect-ratio: 2504\/406;\" \/><\/a><\/p>\n<p>Terminal log&#8217;lar\u0131ndan da g\u00f6rebilece\u011fimiz gibi, publish etmi\u015f oldu\u011fumuz event, geli\u015ftirmi\u015f oldu\u011fumuz service bus library&#8217;si taraf\u0131ndan consume edildikten sonra payload bilgisi ba\u015far\u0131yla ilgili storage account \u00fczerinden al\u0131nm\u0131\u015f ve &#8220;<code>TodoEcom.BillingService.Consumer<\/code>&#8221; projesine kesintisiz bir \u015fekilde consume edebilmesi i\u00e7in iletilmi\u015ftir.<\/p>\n<p data-pm-slice=\"0 0 []\">Bu makale kapsam\u0131nda, conditional claim-check mekanizmas\u0131n\u0131 b\u00fcy\u00fck payload&#8217;lar\u0131 y\u00f6netme s\u00fcre\u00e7lerinde basit bir \u015fekilde nas\u0131l kullanabilece\u011fimizi ele almaya \u00e7al\u0131\u015ft\u0131k. Implemente etmi\u015f oldu\u011fumuz service bus library&#8217;si sayesinde, ilgili consumer&#8217;lar altyap\u0131 i\u015flemlerinden ba\u011f\u0131ms\u0131z olarak event&#8217;lerini kesintisiz bir \u015fekilde publish ve consume etmeye devam ederken, sistemin \u00f6l\u00e7eklenebilirli\u011finin ve verimlili\u011finin minimum d\u00fczeyde etkilenebilmesini sa\u011flamaya \u00e7al\u0131\u015ft\u0131k.<\/p>\n<p data-pm-slice=\"0 0 []\">\u00d6rnek kodlara buradan ula\u015fabilirsiniz: <a href=\"https:\/\/github.com\/GokGokalp\/claim-check-sample\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/GokGokalp\/claim-check-sample<\/a><\/p>\n<h2 data-pm-slice=\"0 0 []\">Referanslar<\/h2>\n<blockquote><p><em>https:\/\/learn.microsoft.com\/en-us\/azure\/architecture\/patterns\/claim-check<br \/>\nhttps:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-dotnet-get-started-with-queues<br \/>\n<\/em><\/p><\/blockquote>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>G\u00fcn\u00fcm\u00fcz teknoloji \u00e7a\u011f\u0131nda, geli\u015ftirdi\u011fimiz uygulama \u00e7\u00f6z\u00fcmlerini olabildi\u011fince \u00f6l\u00e7eklenebilir, dayan\u0131kl\u0131 ve esnek hale getirebilmek i\u00e7in genellikle event-driven architecture temelli yap\u0131lar \u00fczerinde in\u015fa ediyoruz. Event-driven architecture her ne kadar kula\u011fa ho\u015f gelse de beraberinde bir\u00e7ok karma\u015f\u0131kl\u0131k ve limitasyonlar da getirmektedir. Daha \u00f6nceki makalelerim de dayan\u0131kl\u0131 ve esnek&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/gokhan-gokalp.com\/tr\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/\">Devam\u0131n\u0131 okuyun<span class=\"screen-reader-text\">Event-Driven Architecture&#8217;larda Conditional Claim-Check Pattern&#8217;\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":4694,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,68,418,457,285,368],"tags":[713,712,659,286],"class_list":["post-4660","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-architectural","category-azure","category-dotnet","category-messaging","category-microservices","tag-net-9","tag-claim-check","tag-dotnet","tag-messaging","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"tr","enabled_languages":["en","tr"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"tr":{"title":true,"content":true,"excerpt":false}}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Event-Driven Architecture&#039;larda Conditional Claim-Check Pattern&#039;\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek - G\u00f6khan G\u00f6kalp<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Event-Driven Architecture&#039;larda Conditional Claim-Check Pattern&#039;\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek - G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/\" \/>\n<meta property=\"og:site_name\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"article:published_time\" content=\"2024-11-03T20:10:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-12-10T17:38:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/gokhan-gokalp-claim-check-pattern.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"675\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"26 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/\"},\"author\":{\"name\":\"G\u00f6khan G\u00f6kalp\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"headline\":\"Event-Driven Architecture&#8217;larda Conditional Claim-Check Pattern&#8217;\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek\",\"datePublished\":\"2024-11-03T20:10:20+00:00\",\"dateModified\":\"2024-12-10T17:38:18+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/\"},\"wordCount\":3256,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2024\\\/11\\\/gokhan-gokalp-claim-check-pattern.jpg\",\"keywords\":[\".net 9\",\"claim-check\",\"dotnet\",\"Messaging\"],\"articleSection\":[\".NET\",\"Architectural\",\"Azure\",\"dotnet\",\"Messaging\",\"Microservices\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/\",\"name\":\"Event-Driven Architecture'larda Conditional Claim-Check Pattern'\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek - G\u00f6khan G\u00f6kalp\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2024\\\/11\\\/gokhan-gokalp-claim-check-pattern.jpg\",\"datePublished\":\"2024-11-03T20:10:20+00:00\",\"dateModified\":\"2024-12-10T17:38:18+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#primaryimage\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2024\\\/11\\\/gokhan-gokalp-claim-check-pattern.jpg\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2024\\\/11\\\/gokhan-gokalp-claim-check-pattern.jpg\",\"width\":1200,\"height\":675},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Overcoming Event Size Limits with the Conditional Claim-Check Pattern in Event-Driven Architectures\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"description\":\"C# &amp; Python lover\",\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gokhan-gokalp.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"pronouns\":\"he\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"caption\":\"G\u00f6khan G\u00f6kalp\"},\"logo\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\"},\"sameAs\":[\"https:\\\/\\\/gokhan-gokalp.com\"],\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/tr\\\/author\\\/gok-gokalp\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Event-Driven Architecture'larda Conditional Claim-Check Pattern'\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek - G\u00f6khan G\u00f6kalp","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/","og_locale":"tr_TR","og_type":"article","og_title":"Event-Driven Architecture'larda Conditional Claim-Check Pattern'\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek - G\u00f6khan G\u00f6kalp","og_url":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/","og_site_name":"G\u00f6khan G\u00f6kalp","article_published_time":"2024-11-03T20:10:20+00:00","article_modified_time":"2024-12-10T17:38:18+00:00","og_image":[{"width":1200,"height":675,"url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/gokhan-gokalp-claim-check-pattern.jpg","type":"image\/jpeg"}],"author":"G\u00f6khan G\u00f6kalp","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"G\u00f6khan G\u00f6kalp","Tahmini okuma s\u00fcresi":"26 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#article","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/"},"author":{"name":"G\u00f6khan G\u00f6kalp","@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"headline":"Event-Driven Architecture&#8217;larda Conditional Claim-Check Pattern&#8217;\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek","datePublished":"2024-11-03T20:10:20+00:00","dateModified":"2024-12-10T17:38:18+00:00","mainEntityOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/"},"wordCount":3256,"commentCount":0,"publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/gokhan-gokalp-claim-check-pattern.jpg","keywords":[".net 9","claim-check","dotnet","Messaging"],"articleSection":[".NET","Architectural","Azure","dotnet","Messaging","Microservices"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/","url":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/","name":"Event-Driven Architecture'larda Conditional Claim-Check Pattern'\u0131 ile Event Boyut S\u0131n\u0131rlar\u0131n\u0131n \u00dcstesinden Gelmek - G\u00f6khan G\u00f6kalp","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#primaryimage"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/gokhan-gokalp-claim-check-pattern.jpg","datePublished":"2024-11-03T20:10:20+00:00","dateModified":"2024-12-10T17:38:18+00:00","breadcrumb":{"@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/"]}]},{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#primaryimage","url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/gokhan-gokalp-claim-check-pattern.jpg","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2024\/11\/gokhan-gokalp-claim-check-pattern.jpg","width":1200,"height":675},{"@type":"BreadcrumbList","@id":"https:\/\/gokhan-gokalp.com\/overcoming-event-size-limits-with-the-conditional-claim-check-pattern-in-event-driven-architectures\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/gokhan-gokalp.com\/"},{"@type":"ListItem","position":2,"name":"Overcoming Event Size Limits with the Conditional Claim-Check Pattern in Event-Driven Architectures"}]},{"@type":"WebSite","@id":"https:\/\/gokhan-gokalp.com\/#website","url":"https:\/\/gokhan-gokalp.com\/","name":"G\u00f6khan G\u00f6kalp","description":"C# &amp; Python lover","publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gokhan-gokalp.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe","name":"G\u00f6khan G\u00f6kalp","pronouns":"he","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","url":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","caption":"G\u00f6khan G\u00f6kalp"},"logo":{"@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659"},"sameAs":["https:\/\/gokhan-gokalp.com"],"url":"https:\/\/gokhan-gokalp.com\/tr\/author\/gok-gokalp\/"}]}},"_links":{"self":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/4660","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/comments?post=4660"}],"version-history":[{"count":33,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/4660\/revisions"}],"predecessor-version":[{"id":4696,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/4660\/revisions\/4696"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media\/4694"}],"wp:attachment":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media?parent=4660"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/categories?post=4660"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/tags?post=4660"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}