﻿
{"id":28890,"date":"2026-08-23T06:43:48","date_gmt":"2026-08-23T06:43:48","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=28890"},"modified":"2026-08-23T06:43:48","modified_gmt":"2026-08-23T06:43:48","slug":"nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/","title":{"rendered":".NET&#8217;te Tekrarlayan Mimarisel Tasar\u0131m Sorunlar\u0131na Kar\u015f\u0131 \u00c7\u00f6z\u00fcmler"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p><br \/>\nMerhaba,<\/p>\n<p>Bu i\u00e7eri\u011fimizde .NET ile yapt\u0131\u011f\u0131m\u0131z tekrarlayan mimarisel tasar\u0131m sorunlar\u0131na kar\u015f\u0131n nas\u0131l \u00e7\u00f6z\u00fcmler getirebilece\u011fimize dair \u00f6rnek olaylar e\u015fli\u011finde isti\u015fare ediyor olaca\u011f\u0131z. \u00d6zellikle yan etkilerin (side effect) s\u00f6z konusu oldu\u011fu distributed senaryolara odaklanacak ve de\u011ferlendirmede bulunaca\u011f\u0131z. O halde haz\u0131rsan\u0131z hadi ba\u015flayal\u0131m&#8230;<\/p>\n<blockquote style=\"font-size:14px;\"><p><em>Distributed mimarilerde as\u0131l problem \u00e7o\u011fu zaman i\u015flemi yapmak de\u011fil, i\u015flemin yan etkilerinin ne zaman, ka\u00e7 kere ve hangi garantilerle ger\u00e7ekle\u015fti\u011fini kontrol etmektir.<\/em><\/p><\/blockquote>\n<div style=\"margin: 36px 0;padding: 18px 20px;border: 1px solid #c7d2fe;border-radius: 6px;background: #eef2ff;font-family: system-ui, sans-serif;\">\n<div style=\"font-size: 13px;font-weight: 600;color: #3730a3;margin-bottom: 8px;\">\n        Yan Etikeri (Side Effects) Tan\u0131yal\u0131m\n    <\/div>\n<div style=\"font-size: 15px;line-height: 1.7;color: #1e293b;\">\n<div style=\"margin:24px 0;padding:16px 20px;background:#f8f9fb;border-left:4px solid #6366f1;border-radius:8px;color:#4b5563;font-size:14px;line-height:1.6;box-shadow:0 2px 8px rgba(0,0,0,.05);\"><strong style=\"color:#374151;\">Not:<\/strong> Side effect kavram\u0131n\u0131 net bir \u015fekilde anlayabilmek i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/yazilimda-side-effectyan-etki-kavrami-nedir\/\" target=\"_blank\">Yaz\u0131l\u0131mda Side Effect(Yan Etki) Kavram\u0131 Nedir?<\/a> ba\u015fl\u0131kl\u0131 makaleme g\u00f6z atabilirsiniz.<\/div>\n<p>Side effect, bir fonksiyonun kendi \u00e7\u0131kt\u0131s\u0131ndan daha fazlas\u0131n\u0131 de\u011fi\u015ftirmesi durumudur. .NET a\u00e7\u0131s\u0131ndan distributed sistemlerde side effect durumunu 6 ana s\u0131n\u0131fa ay\u0131rabilmemiz m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<table style=\"width:100%;border-collapse:separate;border-spacing:0;font-size:12px;font-family:Arial,sans-serif;border-radius:10px;overflow:hidden;box-shadow:0 3px 12px rgba(0,0,0,.08);\">\n<thead>\n<tr>\n<th style=\"padding:9px 8px;background:#5b4bdb;color:#fff;text-align:left;width:14%;\">T\u00fcr<\/th>\n<th style=\"padding:9px 8px;background:#6c5ce7;color:#fff;text-align:center;width:43%;\">Ne de\u011fi\u015fiyor?<\/th>\n<th style=\"padding:9px 8px;background:#00b894;color:#fff;text-align:center;width:43%;\">\u00d6rnek<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"padding:8px;border-bottom:1px solid #eee;font-weight:600;color:#333;text-align:left;\">State<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;text-align:justify;\">Uygulaman\u0131n\/DB&#8217;nin durumu de\u011fi\u015fkenlik g\u00f6sterir.<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;font-weight:700;color:#00a884;text-align:justify;\">DB <code>UPDATE<\/code>, Redis <code>SET<\/code><\/td>\n<\/tr>\n<tr style=\"background:#f8f9ff;\">\n<td style=\"padding:8px;border-bottom:1px solid #eee;font-weight:600;color:#333;text-align:left;\">I\/O<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;text-align:justify;\">Uygulama d\u0131\u015f\u0131ndaki d\u00fcnyada de\u011fi\u015fkenlik g\u00f6sterir.<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;font-weight:700;color:#00a884;text-align:justify;\">HTTP, dosya, S3, SMTP<\/td>\n<\/tr>\n<tr style=\"background:#f8f9ff;\">\n<td style=\"padding:8px;border-bottom:1px solid #eee;font-weight:600;color:#333;text-align:left;\">Temporal<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;text-align:justify;\">Zaman\/s\u0131ralama davran\u0131\u015flar\u0131ndaki de\u011fi\u015fiklikler kastedilmektedir.<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;font-weight:700;color:#00a884;text-align:justify;\"><code>DateTime.Now<\/code>, retry, timeout<\/td>\n<\/tr>\n<tr style=\"background:#f8f9ff;\">\n<td style=\"padding:8px;border-bottom:1px solid #eee;font-weight:600;color:#333;text-align:left;\">Messaging<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;text-align:justify;\">Mesaj ak\u0131\u015flar\u0131yla ba\u015fka servisleri tetikleyerek de\u011fi\u015fkenlik g\u00f6sterir.<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;font-weight:700;color:#00a884;text-align:justify;\">Kafka\/<a href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-nats-jetstream-ile-calismak\/\" target=\"_blank\">NATS<\/a>\/<a href=\"https:\/\/www.gencayyildiz.com\/blog\/category\/rabbitmq\/\" target=\"_blank\">RabbitMQ<\/a> event publish<\/td>\n<\/tr>\n<tr style=\"background:#f8f9ff;\">\n<td style=\"padding:8px;border-bottom:1px solid #eee;font-weight:600;color:#333;text-align:left;\">Resource<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;text-align:justify;\">Kaynak t\u00fcketimi yahut de\u011fi\u015fimi sa\u011flayabilir.<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;font-weight:700;color:#00a884;text-align:justify;\">Transaction, lock, connection, thread<\/td>\n<\/tr>\n<tr style=\"background:#f8f9ff;\">\n<td style=\"padding:8px;border-bottom:1px solid #eee;font-weight:600;color:#333;text-align:left;\">Observability<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;text-align:justify;\">Monitoring sistemlerinde de\u011fi\u015fkenlik g\u00f6sterir.<\/td>\n<td style=\"padding:8px;text-align:center;border-bottom:1px solid #eee;font-weight:700;color:#00a884;text-align:justify;\">Log, metric, trace<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<\/div>\n<p>Evet, \u015fimdi senaryolara ge\u00e7ebilir ve mimarisel olarak olas\u0131 sorunlara kar\u015f\u0131n nas\u0131l \u00e7\u00f6z\u00fcmler \u00f6nerdi\u011fimize dair isti\u015farede bulunabiliriz;<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_88 counter-hierarchy ez-toc-counter ez-toc-light-blue ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Ba\u015fl\u0131klar<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"\u0130\u00e7indekiler Tablosunu A\u00e7\/Kapat\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/#Senaryo_1_DBye_yazdim_event_publish_edemedim\" >Senaryo 1 : DB&#8217;ye yazd\u0131m, event publish edemedim<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/#Senaryo_2_Eventi_iki_kere_isledim\" >Senaryo 2 : Event&#8217;i iki kere i\u015fledim<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/#Senaryo_3_Exactly-once_denen_sey_esasinda_yok\" >Senaryo 3 : Exactly-once denen \u015fey esas\u0131nda yok!<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/#Senaryo_4_Retry_mekanizmasi_yan_etkiyi_buyutuyor\" >Senaryo 4 : Retry mekanizmas\u0131 yan etkiyi b\u00fcy\u00fct\u00fcyor<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/#Senaryo_5_Saga_Patternda_side_effect_uretebilir\" >Senaryo 5 : Saga Pattern&#8217;da side effect \u00fcretebilir!<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/#Senaryo_6_Distributed_Lock_kullanayim_dedim_isler_daha_da_karisti\" >Senaryo 6 : Distributed Lock kullanay\u0131m dedim, i\u015fler daha da kar\u0131\u015ft\u0131<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.gencayyildiz.com\/blog\/nette-tekrarlayan-mimarisel-tasarim-sorunlarina-karsi-cozumler\/#Senaryo_7_Cache_invalidation_%E2%80%9CDB_guncel_ama_kullanici_eski_veriyi_goruyor%E2%80%9D\" >Senaryo 7 : Cache invalidation: &#8220;DB g\u00fcncel ama kullan\u0131c\u0131 eski veriyi g\u00f6r\u00fcyor&#8221;<\/a><\/li><\/ul><\/nav><\/div>\n<h4><span class=\"ez-toc-section\" id=\"Senaryo_1_DBye_yazdim_event_publish_edemedim\"><\/span>Senaryo 1 : DB&#8217;ye yazd\u0131m, event publish edemedim<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Bir sipari\u015f s\u00fcrecini ele alal\u0131m&#8230; Sipari\u015f geldikten sonra, bu sipari\u015fe dair bilgileri veritaban\u0131na kaydediyor ard\u0131ndan sipari\u015fle alakal\u0131 di\u011fer i\u015flemlerin y\u00fcr\u00fct\u00fclebilmesi i\u00e7in message broker ile di\u011fer servislere event f\u0131rlat\u0131yoruz.<\/p>\n<blockquote style=\"font-size:14px;\"><p><em>\u0130ki ayr\u0131 sisteme ayn\u0131 i\u015f ak\u0131\u015f\u0131 i\u00e7erisinde veri yaz\u0131lmas\u0131 durumlar\u0131na <a href=\"https:\/\/www.gencayyildiz.com\/blog\/tag\/dual-write\/\" target=\"_blank\">Dual Write<\/a> denir.<\/em><\/p><\/blockquote>\n<p>\u015e\u00f6yle ki;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    await dbContext.Orders.AddAsync(order);\r\n    await dbContext.SaveChangesAsync();\r\n\r\n    await eventBus.PublishAsync(new OrderCreated(order.Id));\r\n<\/pre>\n<\/div>\n<p>\u015eimdi b\u00f6yle bir \u00e7al\u0131\u015fmada veritaban\u0131na kay\u0131t yap\u0131ld\u0131ktan sonra message broker&#8217;dan hata al\u0131n\u0131rsa e\u011fer bu durum olduk\u00e7a tehlikeli bir durum arz edecektir. D\u00fc\u015f\u00fcnsenize&#8230; veritaban\u0131nda kay\u0131t var, lakin di\u011fer servislerin bundan haberi yok. B\u00f6yle bir durum b\u00fct\u00fcnsel anlamda alenen tutars\u0131zl\u0131\u011fa mahal verecektir. Keza daha da k\u00f6t\u00fcs\u00fc, bu sipari\u015fe dair uygulaman\u0131n nihai sonucu elde edebilmesi i\u00e7in belki de ilgili veritaban\u0131 i\u015fleminin ba\u015ftan tekrar yap\u0131lmas\u0131 gerekecektir. \u00c7\u00fcnk\u00fc, message broker&#8217;\u0131n hata verdi\u011fi anda veritaban\u0131na kaydedilen sipari\u015fin hi\u00e7bir anlam\u0131 olmayacakt\u0131r.<\/p>\n<p><strong style=\"color:green;\">\u00c7\u00f6z\u00fcm<\/strong><br \/>\n\u0130\u015fte b\u00f6yle bir duruma kar\u015f\u0131n en ideal \u00e7\u00f6z\u00fcm message broker&#8217;a g\u00f6nderilecek verinin Outbox Pattern ile \u00f6nceden farkl\u0131 bir tabloya i\u015flenmesi ve ard\u0131ndan ayr\u0131 bir publisher ile bu tablodan event&#8217;lerin message broker&#8217;a g\u00f6nderilmesidir. Bunun i\u00e7in konuya dair ba\u015ftan sona derinlemesine incelemede bulundu\u011fum <a href=\"https:\/\/www.gencayyildiz.com\/blog\/outbox-design-pattern-nedir-nasil-uygulanir-inbox-pattern-esliginde\/\" target=\"_blank\">Outbox Design Pattern Nedir? Nas\u0131l Uygulan\u0131r? (Inbox Pattern E\u015fli\u011finde)<\/a> ba\u015fl\u0131kl\u0131 makalemi inceleyebilirsiniz.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Senaryo_2_Eventi_iki_kere_isledim\"><\/span>Senaryo 2 : Event&#8217;i iki kere i\u015fledim<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Outbox kullan\u0131nca tabi ki de problemler bitmemektedir \ud83d\ude42 Publisher ile event&#8217;leri message broker&#8217;a g\u00f6nderdi\u011fimizde bu sefer de consumer&#8217;da event&#8217;in received edilme s\u00fcrecinde patlama riski vard\u0131r. \u015e\u00f6yle ki, consumer gelen event&#8217;i i\u015fleyip veritaban\u0131na kaydedebilir ancak ACK g\u00f6ndermeden \u00e7\u00f6kebilir. Haliyle message broker a\u00e7\u0131s\u0131ndan bu durum <em>&#8220;ACK gelmedi, demek ki bu event&#8217;e dair i\u015flem yap\u0131lmad\u0131&#8221;<\/em> olarak yorumlanabilir.<\/p>\n<p><strong style=\"color:green;\">\u00c7\u00f6z\u00fcm<\/strong><br \/>\n\u0130\u015fte burada <a href=\"https:\/\/www.gencayyildiz.com\/blog\/tag\/idempotents\/\" target=\"_blank\">Idempotency<\/a> kavram\u0131 devreye girmektedir. Yani her bir publish edilecek olan event i\u00e7in \u00f6zel bir anahtar, token veya id gibi de\u011fer \u00fcretecek ve consumer&#8217;da bu de\u011ferle birlikte ilgili event&#8217;in i\u015flendi\u011fine dair veritaban\u0131na kay\u0131t ataca\u011f\u0131z. B\u00f6ylece consumer&#8217;a gelen her event&#8217;i kontroll\u00fc bir \u015fekilde i\u015fleme tabi tutacak ve \u00f6nceden bir kay\u0131t yoksa g\u00f6n\u00fcl rahatl\u0131\u011f\u0131yla i\u015fleyerek tutarl\u0131l\u0131k a\u00e7\u0131s\u0131ndan g\u00fcvence sa\u011flayaca\u011f\u0131z!<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Senaryo_3_Exactly-once_denen_sey_esasinda_yok\"><\/span>Senaryo 3 : Exactly-once denen \u015fey esas\u0131nda yok!<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<div style=\"display:flex;gap:0;max-width:100%;margin:20px auto;border-radius:18px;overflow:hidden;box-shadow:0 8px 30px rgba(0,0,0,.12);font-family:Arial,sans-serif;\">\n<div style=\"flex:1;padding:28px;background:#f3f7ff;color:#183153;text-align:center;\">\n<div style=\"font-size:15px;font-weight:700;margin-bottom:12px;\">Exactly-once delivery<\/div>\n<div style=\"font-size:13px;line-height:1.7;\">Bir mesaj\u0131n consumer&#8217;a tam olarak bir kez ula\u015ft\u0131r\u0131lmas\u0131d\u0131r.\n<\/div>\n<\/div>\n<div style=\"width:70px;background:#fff;display:flex;align-items:center;justify-content:center;color:#64748b;font-size:26px;font-weight:700;\">\u2194<\/div>\n<div style=\"flex:1;padding:28px;background:#fff7f2;color:#59321f;text-align:center;\">\n<div style=\"font-size:15px;font-weight:700;margin-bottom:12px;\">Exactly-once business effect<\/div>\n<div style=\"font-size:13px;line-height:1.7;\">O mesaj\u0131n temsil etti\u011fi i\u015f operasyonunun tam olarak bir kez ger\u00e7ekle\u015fmesidir.\n<\/div>\n<\/div>\n<\/div>\n<p>Event&#8217;in consumer&#8217;a bir kez ula\u015ft\u0131r\u0131lmas\u0131, <em>exactly-once business effect<\/em> garantisi vermeyecektir. Event consumer&#8217;a ula\u015ft\u0131ktan sonra business i\u015flem sistemin geri kalan\u0131nda istenilen atomiklikte tamamlanamayabilir:<\/p>\n<p><code>Event geliyor<\/code> \u2794 <code>Para \u00e7ekiliyor<\/code> \u2794 <code>ACK g\u00f6nderilecek<\/code> \u2794 \ud83d\udca5<\/p>\n<p>Para \u00e7ekme i\u015flemi ba\u015far\u0131yla ger\u00e7ekle\u015fmi\u015fken consuemr ACK g\u00f6ndermeden \u00e7\u00f6kerse e\u011fer, sistem event&#8217;in i\u015flenip i\u015flenmedi\u011fini kesin olarak bilemeyecektir. Consumer&#8217;\u0131n retry\/recovery mekanizmas\u0131 devreye girdi\u011finde ayn\u0131 event yeniden i\u015flenebilir ve para \u00e7ekme gibi non-idempotent bir business operation birden fazla kez \u00e7al\u0131\u015ft\u0131r\u0131labilir.<\/p>\n<p>Ayn\u0131 durum request\/response s\u00fcre\u00e7leri i\u00e7in de ge\u00e7erlidir. Kullan\u0131c\u0131dan gelen bir request neticesinde i\u015flem ger\u00e7ekle\u015ftirilebilir ama sonras\u0131nda t\u00fcrl\u00fc nedenlerden kaynakl\u0131 istek timeout&#8217;a d\u00fc\u015febilir. B\u00f6yle bir durumda kullan\u0131c\u0131n\u0131n fark\u0131nda olmaks\u0131z\u0131n tekrar ayn\u0131 iste\u011fi ger\u00e7ekle\u015ftirmesi y\u00fcksek olas\u0131d\u0131r. Haliyle ayn\u0131 i\u015flem tekrar ger\u00e7ekle\u015ftirilmi\u015f olacakt\u0131r.<\/p>\n<p>Dolay\u0131s\u0131yla <em>exactly-once delivery<\/em> ile <em>exactly-once business effect<\/em> ayn\u0131 problemler de\u011fildir. \u0130lki mesaj\u0131n consumer&#8217;a ka\u00e7 kez ula\u015ft\u0131\u011f\u0131yla ilgilenirken, ikincisi ise mesaj\u0131n tetiklendi\u011fi business i\u015flemin etkili olarak ka\u00e7 kez ger\u00e7ekle\u015fti\u011fiyle ilgilenir.<\/p>\n<p><strong style=\"color:green;\">\u00c7\u00f6z\u00fcm<\/strong><br \/>\nBu tarz durumlara kar\u015f\u0131n yine <a href=\"https:\/\/www.gencayyildiz.com\/blog\/tag\/idempotents\/\" target=\"_blank\">Idempotency<\/a> kavram\u0131 olduk\u00e7a ideal \u00e7\u00f6z\u00fcm getirmektedir.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Senaryo_4_Retry_mekanizmasi_yan_etkiyi_buyutuyor\"><\/span>Senaryo 4 : Retry mekanizmas\u0131 yan etkiyi b\u00fcy\u00fct\u00fcyor<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>\u015e\u00f6yle bir kod olduk\u00e7a masum g\u00f6r\u00fcn\u00fcyor olabilir&#8230;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nawait retryPolicy.ExecuteAsync(async () =&gt;\r\n{\r\n    await paymentService.ChargeAsync(order);\r\n});\r\n<\/pre>\n<\/div>\n<p>Ancak burada <code>ChargeAsync<\/code> metodu idempotent de\u011filse e\u011fer retry davran\u0131\u015f\u0131 <em>-hata olursa i\u015flemi tekrar yap-<\/em> \u015feklinde de\u011fil, <em>-belirsizlik durumunda yan etkiyi tekrar \u00fcret-<\/em> \u015feklinde bir varl\u0131k g\u00f6sterecektir.<\/p>\n<p><strong style=\"color:green;\">\u00c7\u00f6z\u00fcm<\/strong><br \/>\nBurada \u00e7\u00f6z\u00fcmden ziyade dikkat edilmesi gereken noktalar\u0131 \u015f\u00f6yle genelleyebiliriz; e\u011fer retry mekanizmas\u0131 <code>GET<\/code>, <code>DB SELECT<\/code> vs. gibi okuma i\u015flemlerinde kullan\u0131l\u0131yorsa olduk\u00e7a g\u00fcvenlidir, ancak <code>PUT<\/code> ve <code>POST<\/code> i\u015flemlerinde kesinlikle idempotency ile hareket edilmelidir.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Senaryo_5_Saga_Patternda_side_effect_uretebilir\"><\/span>Senaryo 5 : Saga Pattern&#8217;da side effect \u00fcretebilir!<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Diyelim ki \u015f\u00f6yle a\u015fa\u011f\u0131daki gibi bir sipari\u015f s\u00fcreci olsun;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:550px;font-size:14px;\">Order Service \u2794 Payment Service \u2794 Inventory Service \u2794 Shipping Service\n<\/div>\n<p>Burada her servisin kendi transaction&#8217;\u0131na sahip oldu\u011funu d\u00fc\u015f\u00fcnelim.<\/p>\n<p>\u015eimdi varsayal\u0131m ki bir sipari\u015fin i\u015flenmesi s\u00fcrecinde \u015fu sorun meydana gelmi\u015f olsun;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:130px;font-size:14px;\">Order \u2713<br \/>\nPayment \u2713<br \/>\nInventory \u2713<br \/>\nShipping \u2717\n<\/div>\n<p><strong style=\"color:green;\">\u00c7\u00f6z\u00fcm<\/strong><br \/>\nB\u00f6yle bir durumda SQL transaction rollback yap\u0131lamaz \u00e7\u00fcnk\u00fc, t\u00fcm bu servislerin her biri ayr\u0131 sistemlerdir. Dolay\u0131s\u0131yla burada Saga ile bir kontrol sa\u011flamal\u0131 ve gerekti\u011fi taktirde <a href=\"https:\/\/www.gencayyildiz.com\/blog\/tag\/compensable-transaction-nedir\/\" target=\"_blank\">compensation transaction<\/a> davran\u0131\u015f\u0131 uygulanmal\u0131d\u0131r.<\/p>\n<p>Ayr\u0131ca Saga i\u00e7in kesinlikle \u015fu makalelere g\u00f6z atman\u0131z\u0131 tavsiye etmekteyim;<\/p>\n<ul style=\"font-size:14px;\"<a href=\"https:\/\/www.gencayyildiz.com\/blog\/microservice-saga-commands-orchestration-implemantasyonu-ile-transaction-yonetimi\/\" target=\"_blank\">Microservice \u2013 Saga \u2013 Commands\/Orchestration Implemantasyonu \u0130le Transaction Y\u00f6netimi<\/a>><\/p>\n<li><a href=\"https:\/\/www.gencayyildiz.com\/blog\/microservice-mimarilerde-saga-pattern-ile-transaction-yonetimi\/\" target=\"_blank\">Microservice Mimarilerde Saga Pattern \u0130le Transaction Y\u00f6netimi<\/a><\/li>\n<li><a href=\"https:\/\/www.gencayyildiz.com\/blog\/microservice-saga-events-choreography-implemantasyonu-ile-transaction-yonetimi\/\" target=\"_blank\">Microservice \u2013 Saga \u2013 Events\/Choreography Implemantasyonu \u0130le Transaction Y\u00f6netimi<\/a><\/li>\n<li><a href=\"https:\/\/www.gencayyildiz.com\/blog\/microservice-saga-commands-orchestration-implemantasyonu-ile-transaction-yonetimi\/\" target=\"_blank\">Microservice \u2013 Saga \u2013 Commands\/Orchestration Implemantasyonu \u0130le Transaction Y\u00f6netimi<\/a><\/li>\n<\/ul>\n<p>Tabi burada \u015funa dikkat etmekte de fayda g\u00f6rmekteyim. Compensation bir rollback de\u011fildir. \u00c7\u00fcnk\u00fc <code>ChargePayment()<\/code> i\u015fleminin matematiksel olarak <code>RollbackPayment()<\/code> diye bir kar\u015f\u0131l\u0131\u011f\u0131 tabi ki de yoktur! Onun yerine <code>RefundPayment()<\/code> davran\u0131\u015f\u0131 daha ideal olacakt\u0131r! Bu a\u00e7\u0131dan bak\u0131ld\u0131\u011f\u0131nda evet, Saga&#8217;n\u0131n kendisi de yeni side effect&#8217;ler \u00fcretmektedir.<\/p>\n<h4><span class=\"ez-toc-section\" id=\"Senaryo_6_Distributed_Lock_kullanayim_dedim_isler_daha_da_karisti\"><\/span>Senaryo 6 : Distributed Lock kullanay\u0131m dedim, i\u015fler daha da kar\u0131\u015ft\u0131<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Varsayal\u0131m ki iki instance ayn\u0131 job&#8217;\u0131 \u00e7al\u0131\u015ft\u0131r\u0131yor olsun;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:260px;font-size:14px;\">Instance A \u2500\u2500\u2510<br \/>\n             \u251c\u2500\u2500\u25ba GenerateInvoice()<br \/>\nInstance B \u2500\u2500\u2518\n<\/div>\n<p>Burada g\u00f6r\u00fclen olas\u0131 riske kar\u015f\u0131 tabi ki de \u00e7\u00f6z\u00fcm olarak distributed lock ak\u0131llara gelecektir. Ancak burada <strong><em>Time To Live (TTL)<\/em><\/strong> ile ilgili bir durum s\u00f6z konusudur.<\/p>\n<blockquote style=\"font-size:14px;\"><p><em>TTL, koyulan lock&#8217;\u0131n ne kadar s\u00fcre ge\u00e7erli kalaca\u011f\u0131n\u0131 ifade eden bir terimdir.<\/em><\/p><\/blockquote>\n<p>Mesela:<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">Lock: order-processing<br \/>\nTTL: 30 saniye\n<\/div>\n<p>\u015feklinde bir yap\u0131land\u0131rmadan 30 saniyelik bir kilitleme durumunun s\u00f6z konusu olaca\u011f\u0131 anla\u015f\u0131lmaktad\u0131r. Yani 30 saniye sonra lock otomatik olarak silinecektir. Burada ak\u0131llara \u015fu soru gelebilir: <strong><em>Neden lock&#8217;a TTL koyuyoruz?<\/em><\/strong> El-cevap, bunun nedeni lock&#8217;\u0131 alan server&#8217;\u0131n\/instance&#8217;\u0131n \u00f6lme ihtimalidir. E\u011fer al\u0131nan lock&#8217;un TTL&#8217;i yoksa bu lock sonsuza kadar tutuldu\u011fu storage&#8217;da (\u00f6rne\u011fin Redis) kalabilir ve b\u00f6ylece sistem kilitlenebilir. B\u00f6ylece TTL sayesinde lock&#8217;\u0131 alan server \u00f6lse dahi belirtilen s\u00fcre kadar sonra lock&#8217;un kendili\u011finden ortadan kalkaca\u011f\u0131n\u0131n garantisini vermi\u015f oluyoruz.<\/p>\n<p>\u0130\u015fte distributed lock s\u00fcre\u00e7lerinde tehlikeli nokta tamda burada s\u00f6z konusu olabilmektedir. Diyelim ki A instance&#8217;\u0131 TTL 30 saniye olacak \u015fekilde lock&#8217;u ald\u0131 ve i\u015f yapmaya ba\u015flad\u0131. Ve varsayal\u0131m ki i\u015flemin 10 saniye civar\u0131nda s\u00fcrmesi bekleniyordu. Ancak beklenmeyen bir durum s\u00f6z konusu oldu ve A instance&#8217;\u0131n\u0131n i\u015flemi haddinden uzun s\u00fcrmeye ba\u015flad\u0131 ve TTL zaman\u0131 dolarak expire oldu. Art\u0131k yap\u0131lan i\u015flemle ilgili bir lock yok! Haliyle A instance&#8217;\u0131n\u0131n i\u015flemi devam ederken B instance&#8217;\u0131 da storage&#8217;dan lock isteyebilir ve lock olmad\u0131\u011f\u0131 i\u00e7in i\u015flem s\u00fcrecinde yeni bir lock edinerek A instance&#8217;\u0131 hala \u00e7al\u0131\u015f\u0131rken i\u015flemlere ba\u015flayabilir. <\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:250px;font-size:14px;\">A \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba i\u015flem<br \/>\n                    i\u015flem<br \/>\n                    i\u015flem<\/p>\n<p>B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25ba i\u015flem\n<\/p><\/div>\n<p>Bu vaziyette son duruma bakarsak e\u011fer her iki instance g\u00f6z\u00fcnden de lock sahibi oldu\u011fu san\u0131lmaktad\u0131r. Ancak storage&#8217;a gidersek son durumda B instance&#8217;\u0131n\u0131n lock sahibi oldu\u011fu g\u00f6r\u00fclecektir. Yani arap sa\u00e7\u0131 misali bir problem durumuyla kar\u015f\u0131 kar\u015f\u0131ya kal\u0131nd\u0131\u011f\u0131 a\u015fikard\u0131r.<\/p>\n<p>\u015e\u00f6yle bir senaryoyla d\u00fc\u015f\u00fcnsenize:<\/p>\n<div style=\"display: flex; width: 100%; gap: 20px;\">\n<div style=\"flex: 1; box-sizing: border-box; padding: 20px;\">\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">A<br \/>\n \u2193<br \/>\nRedis lock<br \/>\n \u2193<br \/>\nSipari\u015fi i\u015fle<br \/>\n \u2193<br \/>\nBankadan para \u00e7ek\n<\/div>\n<\/p><\/div>\n<div style=\"flex: 1; box-sizing: border-box; padding: 20px;\">\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">B<br \/>\n \u2193<br \/>\nYeni lock ald\u0131<br \/>\n \u2193<br \/>\nAyn\u0131 sipari\u015fi i\u015fle<br \/>\n \u2193<br \/>\nBankadan para \u00e7ek\n<\/div>\n<\/p><\/div>\n<\/div>\n<p>Fark\u0131ndaysan\u0131z buradaki as\u0131l problem lock&#8217;\u0131n bozulmas\u0131 de\u011fil, lock&#8217;\u0131n ge\u00e7erlili\u011fi bitmesine ra\u011fmen ilgili server&#8217;\u0131n kendini hala yetkili sanmas\u0131d\u0131r. Bu \u00e7ok \u00f6nemli ve kritik bir distributed systems problemidir.<\/p>\n<blockquote style=\"font-size:14px;color:green;\"><p><em>Distribured lock, distributed consistency problemini ortadan kald\u0131rmamakta, yaln\u0131zca belirli bir concurrency problemini y\u00f6netmektedir.<\/em><\/p><\/blockquote>\n<p><strong style=\"color:green;\">\u00c7\u00f6z\u00fcm<\/strong><br \/>\n\u00c7\u00f6z\u00fcm olarak bu tarz bir durumda TTL&#8217;i s\u00fcrekli yenilemek akla gelebilir. Evet, bu m\u00fcmk\u00fcnd\u00fcr de&#8230; Ki b\u00f6ylece lock yap\u0131lan i\u015flem s\u00fcreci boyunca canl\u0131 tutulacakt\u0131r.<\/p>\n<blockquote style=\"font-size:14px;\"><p><em>TTL&#8217;in s\u00fcrekli yenilenmesi davran\u0131\u015f\u0131na <strong>lock renewal<\/strong> veya <strong>lease renewal<\/strong> denmektedir.<\/em><\/p><\/blockquote>\n<p>Ancak burada yeni problemler de s\u00f6z konusu olabilir. Misal olarak server ile lock TTL&#8217;inin tutuldu\u011fu storage aras\u0131ndaki ba\u011flant\u0131 koparsa art\u0131k TTL yenilenemeyecektir ve daha da k\u00f6t\u00fcs\u00fc ilgili server hala \u00e7al\u0131\u015f\u0131rken di\u011fer server storage&#8217;dan lock al\u0131p m\u00fckerrer i\u015flem durumu s\u00f6z konusu olabilecektir.<\/p>\n<p>Bu tarz bir duruma kar\u015f\u0131n \u00e7\u00f6z\u00fcm getirebilmek i\u00e7in <em><strong>Fencing Token<\/strong><\/em> kavram\u0131 geli\u015ftirilmi\u015ftir.<\/p>\n<div style=\"margin: 36px 0;padding: 18px 20px;border: 1px solid #c7d2fe;border-radius: 6px;background: #eef2ff;font-family: system-ui, sans-serif;\">\n<div style=\"font-size: 13px;font-weight: 600;color: #3730a3;margin-bottom: 8px;\">\n        Fencing Token\n    <\/div>\n<div style=\"font-size: 15px;line-height: 1.7;color: #1e293b;\">\nDistributed lock&#8217;\u0131n s\u00fcresi dolduktan sonra eski lock sahibinin hala i\u015flem yapmas\u0131n\u0131 engellemek i\u00e7in kullan\u0131lan bir davran\u0131\u015ft\u0131r.<\/p>\n<p>\u0130\u015flem mant\u0131\u011f\u0131 olduk\u00e7a basittir: s\u0131ral\u0131 bir numara gibi \u00e7al\u0131\u015fma sergiler.<\/p>\n<p>Diyelim ki;<br \/>\nA instance&#8217;\u0131 lock al\u0131yor&#8230;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">A \u2192 Lock ald\u0131 \u2192 Token = 41\n<\/div>\n<p>ve \u00e7al\u0131\u015fmaya ba\u015fl\u0131yor.<\/p>\n<p>Sonra lock&#8217;\u0131n TTL&#8217;i doluyor ve B gelip lock al\u0131yor&#8230;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">B \u2192 Lock ald\u0131 \u2192 Token = 42\n<\/div>\n<p>Son durumda;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">A = 41  \u2190 eski<br \/>\nB = 42  \u2190 yeni\n<\/div>\n<p>\u015feklinde bir vaziyet s\u00f6z konusu oluyor.<\/p>\n<p>Haliyle bu vaziyette A hala \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 san\u0131p database&#8217;e bir \u015fey yazmaya \u00e7al\u0131\u015f\u0131rsa;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:360px;font-size:14px;\">A \u2192 &#8220;Ben 41 token&#8217;l\u0131y\u0131m.&#8221;<br \/>\nDB \u2192 &#8220;Hay\u0131r. En son 42&#8217;yi g\u00f6rd\u00fcm. Sen eskisin.&#8221;\n<\/div>\n<p>\u015feklinde bir \u00f6nlemle i\u015flem reddediliyor.\n    <\/p><\/div>\n<\/div>\n<blockquote style=\"font-size:14px;\"><p><em>Unutmay\u0131n! Bir distributed lock&#8217;\u0131n sahibi olmak, i\u015flemin geri kalan\u0131nda hala yetkili olundu\u011funun garantisini vermemektedir!<\/em><\/p><\/blockquote>\n<h4><span class=\"ez-toc-section\" id=\"Senaryo_7_Cache_invalidation_%E2%80%9CDB_guncel_ama_kullanici_eski_veriyi_goruyor%E2%80%9D\"><\/span>Senaryo 7 : Cache invalidation: &#8220;DB g\u00fcncel ama kullan\u0131c\u0131 eski veriyi g\u00f6r\u00fcyor&#8221;<span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p>Redis&#8217;te cache&#8217;lenmi\u015f bir verinin veritaban\u0131nda g\u00fcncellenmesi durumunda cache&#8217;deki halinin de ya g\u00fcncellenmesi ya da silinmesi gerekti\u011fini hepimiz biliyoruz. Ancak distributed bir mimaride burada bir risk te\u015fkil etti\u011fine dikkatinizi \u00e7ekmek isterim.<\/p>\n<p>Diyelim ki a\u015fa\u011f\u0131daki gibi iki adet API instance&#8217;\u0131m\u0131z olsun&#8230;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">        Load Balancer<br \/>\n         \/         \\<br \/>\n        \/           \\<br \/>\nInstance A       Instance B<br \/>\n     \u2502                 \u2502<br \/>\n     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<br \/>\n            \u2502<br \/>\n          Redis<br \/>\n            \u2502<br \/>\n        SQL Server\n<\/div>\n<p>\u00d6rne\u011fin kullan\u0131c\u0131 taraf\u0131ndan cache&#8217;lenmi\u015f bir verinin orjinal veritaban\u0131nda g\u00fcncellendi\u011fini ve bu talebin A instance&#8217;\u0131 \u00fczerinden al\u0131nd\u0131\u011f\u0131n\u0131 varsayal\u0131m. Burada ak\u0131\u015f \u015f\u00f6yle olacakt\u0131r;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">User<br \/>\n  \u2193<br \/>\nInstance A<br \/>\n  \u2193<br \/>\n[Update] Data<br \/>\n  \u2193<br \/>\n[Delete or Update] Cache\n<\/div>\n<p>Ancak farkl\u0131 bir kullan\u0131c\u0131 taraf\u0131ndan gelen ba\u015fka bir talepte ise cache&#8217;lenmi\u015f verinin okundu\u011funu bunu da B instance&#8217;\u0131n\u0131n kar\u015f\u0131lad\u0131\u011f\u0131n\u0131 varsayal\u0131m.<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">User<br \/>\n \u2193<br \/>\nInstance B<br \/>\n \u2193<br \/>\nRedis<br \/>\n \u2193<br \/>\n???\n<\/div>\n<p>\u0130\u015fte tam da burada zaman olduk\u00e7a \u00f6nemlidir&#8230; A instance&#8217;\u0131 veritaban\u0131 g\u00fcncelledikten sonra cache&#8217;i hen\u00fcz silemeden ya da g\u00fcncellemeden tam o s\u0131rada B instance&#8217;\u0131 taraf\u0131ndan cache&#8217;deki veri okunursa e\u011fer i\u015fte burada bir tutars\u0131zl\u0131k durumu s\u00f6z konusu olabilir!<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:340px;font-size:14px;\">A                      B<br \/>\n\u2502                      \u2502<br \/>\n\u2502 DB \u2192 [New Data]      \u2502<br \/>\n\u2502                      \u2502<br \/>\n\u2502                      \u251c\u2500\u2500 Redis \u2192 [Old Data]<br \/>\n\u2502                      \u2502<br \/>\n\u251c\u2500\u2500 Cache Delete       \u2502<br \/>\n\u2502                      \u2502\n<\/div>\n<p>\u0130\u015fte bu vaziyette ortaya \u00e7\u0131kan probleme <strong><em>cache invalidation<\/em><\/strong> diyoruz&#8230;<\/p>\n<blockquote style=\"font-size:14px;\"><p><em>Cache Invalidation; ger\u00e7ek veri de\u011fi\u015fti\u011finde, onun cache&#8217;teki eski kopyas\u0131n\u0131 ne zaman ve nas\u0131l ge\u00e7ersiz hale getirece\u011fiz? problemidir!<\/em><\/p><\/blockquote>\n<p>Keza burada bahsetti\u011fimiz problem bir tek cache&#8217;in kullan\u0131lmad\u0131\u011f\u0131 senaryolar i\u00e7in daha y\u0131k\u0131c\u0131 olacakt\u0131r. D\u00fc\u015f\u00fcnsenize, a\u015fa\u011f\u0131daki gibi daha ger\u00e7ek\u00e7i bir durumda;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">          SQL Server<br \/>\n              \u2502<br \/>\n   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510<br \/>\n   \u2193          \u2193          \u2193<br \/>\n Redis    Elasticsearch  CDN<br \/>\n   \u2502          \u2502          \u2502<br \/>\n   \u2193          \u2193          \u2193<br \/>\nAPI cache   Search      Web\n<\/div>\n<p>veritaban\u0131ndaki bir de\u011fi\u015fikli\u011fin esas\u0131nda buradaki t\u00fcm yap\u0131lanmalara yans\u0131t\u0131lmas\u0131 gerekmektedir. Bu durumda da <strong><em>side effect explosion<\/em><\/strong> (yan etki patlamas\u0131) ad\u0131n\u0131 verdi\u011fimiz durum cereyan edecektir. \u00c7\u00fcnk\u00fc bir fiziksel de\u011fi\u015fiklik ayn\u0131 zamanda hem cache&#8217;e, hem Elasticsearch&#8217;e hem de CDN&#8217;e yans\u0131t\u0131lacakt\u0131r&#8230; Ha yans\u0131t\u0131lm\u0131yor mu? Bu da farkl\u0131 bir s\u0131*\u0131\u015f senaryosuna kar\u015f\u0131l\u0131k gelecektir.<\/p>\n<p>\u00d6rnek durumu daha da derinle\u015ftirirsek e\u011fer;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nawait productRepository.UpdateAsync(product);\r\n\r\nawait redis.RemoveAsync($&quot;product:{product.Id}&quot;);\r\n\r\nawait searchIndex.UpdateAsync(product);\r\n\r\nawait cdn.InvalidateAsync(product.Id);\r\n\r\nawait eventBus.PublishAsync(new ProductUpdated(product.Id));\r\n<\/pre>\n<\/div>\n<p>vaziyetini ele alal\u0131m. Burada;<\/p>\n<div style=\"background:#0d0d0d;color:#e6e6e6;font-family:Consolas,'Courier New',monospace;white-space:pre;line-height:0.8;padding:12px;width:230px;font-size:14px;\">DB update \u2713<br \/>\nRedis delete \u2713<br \/>\nSearch update \u2713<br \/>\nCDN invalidate \u2717<br \/>\nEvent publish &#8230;\n<\/div>\n<p>\u015feklinde bir durumun s\u00f6z konusu oldu\u011funu varsayal\u0131m. Yani dikkat ederseniz DB, Redis ve Elasticsearch tutarl\u0131yken CDN&#8217;de bir \u00e7\u00f6kme meydana geldi\u011fi i\u00e7in tutarl\u0131l\u0131k bozulmaktad\u0131r. Yani art\u0131k sistemin farkl\u0131 noktalar\u0131nda ayn\u0131 \u00fcr\u00fcn\u00fcn farkl\u0131 ger\u00e7ekleri mevcuttur.<\/p>\n<p>\u0130\u015fte t\u00fcm bu vurgulad\u0131\u011f\u0131m\u0131z senaryolar ger\u00e7ekten kar\u015f\u0131la\u015f\u0131labilecek kritik durumlard\u0131r.<br \/>\n<strong style=\"color:green;\">\u00c7\u00f6z\u00fcm<\/strong><br \/>\nAna veri g\u00fcncellendi\u011fi her an cache&#8217;i de g\u00fcncellemeye yahut silmeye \u00f6zen g\u00f6sterilmelidir. Ancak cache&#8217;deki bu i\u015flem ba\u015far\u0131s\u0131z olursa yine tutars\u0131zl\u0131k mevzu bahis olaca\u011f\u0131 i\u00e7in dikkat edilmelidir. E\u011fer ki, sistemin ba\u011f\u0131ml\u0131l\u0131\u011f\u0131 bir tek Redis de\u011filse (yani Elasticsearch, CDN vs. varsa) bu servislere do\u011frudan tek tek m\u00fcdahale etmek yerine event-driven bir davran\u0131\u015fla <code>Updated<\/code> event&#8217;i yay\u0131nlanabilir ve bu event yay\u0131nland\u0131\u011f\u0131nda sisteme ba\u011fl\u0131 olan t\u00fcm harici servislere gerekli m\u00fcdahalede bulunulabilir. Bu daha do\u011fru ve esnetilebilir bir yakla\u015f\u0131m olacakt\u0131r. Ancak g\u00fcvenilir olabilmesi i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/outbox-design-pattern-nedir-nasil-uygulanir-inbox-pattern-esliginde\/\" target=\"_blank\">Outbox pattern<\/a> ile birlikte <a href=\"https:\/\/www.gencayyildiz.com\/blog\/tag\/inbox-pattern\/\" target=\"_blank\">Inbox pattern<\/a>&#8216;\u0131 uygulamak gerekecektir. \u00c7\u00fcnk\u00fc bu event&#8217;in kaybolma kayg\u0131s\u0131 ile birlikte duplicate olarak i\u015flenmesi durumlar\u0131 da ka\u00e7\u0131n\u0131lmaz olarak mevzu bahis olacakt\u0131r. Eee event kavram\u0131n\u0131n ve Outbox davran\u0131\u015f\u0131n\u0131n oldu\u011fu yerde de ister istemez m\u00fckerrer i\u015flemlere de dikkat edilmesi gerekecek ve sistemin idempotent olarak tasarlanmas\u0131 da gerekecektir.<\/p>\n<p>Nihai olarak;<br \/>\nFark edildi\u011fi \u00fczere bir\u00e7ok senaryoda Idempotency, Outbox \/ Inbox, Saga ve benzeri pattern&#8217;lar s\u00fcrekli kar\u015f\u0131m\u0131za \u00e7\u0131kmaktad\u0131r. Bunun temel sebebi, distributed sistemlerde ba\u015far\u0131s\u0131zl\u0131klar\u0131n istisnai durumlar de\u011fil, tasar\u0131m\u0131n do\u011fal bir par\u00e7as\u0131 olmas\u0131d\u0131r.<\/p>\n<p>Dolay\u0131s\u0131yla bir sistemi tasarlarken bu pattern&#8217;lar\u0131 yaln\u0131zca ihtiya\u00e7 ortaya \u00e7\u0131kt\u0131\u011f\u0131nda ba\u015fvurulacak \u00e7\u00f6z\u00fcmler olarak g\u00f6rmek yerine, olas\u0131 ba\u015far\u0131s\u0131zl\u0131k senaryolar\u0131n\u0131, tekrar \u00e7al\u0131\u015ft\u0131r\u0131lmalar\u0131 ve olu\u015fabilecek side effect&#8217;leri daha en ba\u015ftan hesaba katarak mimariyi \u015fekillendirmek gerekmektedir.<\/p>\n<p>As\u0131l hedef, t\u00fcm bu pattern&#8217;lar\u0131 sisteme dahil etmek de\u011fil, sistemin hangi noktalar\u0131nda tekrar, belirsizlik, k\u0131smi ba\u015far\u0131s\u0131zl\u0131k ve yan etki olu\u015fabilece\u011fini \u00f6nceden g\u00f6rerek, bunlara kar\u015f\u0131 do\u011fru garantileri tasar\u0131m\u0131n bir par\u00e7as\u0131 haline getirmektir. B\u00f6ylece mimariyi sonradan yamalarla d\u00fczeltmek yerine, daha ilk g\u00fcnden g\u00fcvenilir, \u00f6ng\u00f6r\u00fclebilir ve ba\u015far\u0131s\u0131zl\u0131klar kar\u015f\u0131s\u0131nda dayan\u0131kl\u0131 bir yap\u0131ya do\u011fru evriltmemiz en do\u011fru ve ideal zemini sa\u011fl\u0131yor olacakt\u0131r.<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Bu i\u00e7eri\u011fimizde .NET ile yapt\u0131\u011f\u0131m\u0131z tekrarlayan mimarisel tasar\u0131m sorunlar\u0131na kar\u015f\u0131n nas\u0131l \u00e7\u00f6z\u00fcmler getirebilece\u011fimize dair \u00f6rnek olaylar e\u015fli\u011finde isti\u015fare ediyor olaca\u011f\u0131z. \u00d6zellikle yan etkilerin (side effect) s\u00f6z konusu oldu\u011fu distributed senaryolara odaklanacak ve de\u011ferlendirmede&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":28910,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5206,3102,3573],"tags":[5759,5753,5752,5758,5756,5757,5760,5754,5755],"class_list":["post-28890","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-asp-net-core","category-microservices","tag-cache-invalidation","tag-exactly-once-business-effect","tag-exactly-once-delivery","tag-fencing-token","tag-lease-renewal","tag-lock-renewal","tag-side-effect-explosion","tag-time-to-live","tag-ttl"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/28890","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=28890"}],"version-history":[{"count":17,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/28890\/revisions"}],"predecessor-version":[{"id":28909,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/28890\/revisions\/28909"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/28910"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=28890"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=28890"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=28890"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}