﻿
{"id":26319,"date":"2023-05-07T22:14:42","date_gmt":"2023-05-07T22:14:42","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=26319"},"modified":"2023-05-07T22:15:32","modified_gmt":"2023-05-07T22:15:32","slug":"event-driven-mimaride-yinelenen-mesajlar-idempotent-sorunsali-ve-idempotent-consumer-pattern","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/event-driven-mimaride-yinelenen-mesajlar-idempotent-sorunsali-ve-idempotent-consumer-pattern\/","title":{"rendered":"Event-Driven Mimaride Yinelenen Mesajlar &#8211; Idempotent Sorunsal\u0131 ve Idempotent Consumer Pattern"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Yaz\u0131l\u0131m olgusu, tabiat\u0131 gere\u011fi birbiriyle etkile\u015fim kurma mecburiyetinde olan farkl\u0131 bile\u015fenlerden meydana gelip, anatomik olarak b\u00fct\u00fcnl\u00fck arz eden bir olgudur. Bu b\u00fct\u00fcnl\u00fc\u011f\u00fcn i\u00e7erisindeki bile\u015fenler aras\u0131ndaki etkile\u015fimi modelleyebilmemizi sa\u011flayan t\u00fcrl\u00fc yakla\u015f\u0131mlar mevcuttur ve bu yakla\u015f\u0131mlar\u0131n aras\u0131ndan <em>Event-Driven Architecture<\/em>(EDA) etkin olarak olay tabanl\u0131 bir model ortaya koymaktad\u0131r. Bu yakla\u015f\u0131mda, bir bile\u015fen etkile\u015fim kurmak istedi\u011fi di\u011fer bile\u015fen(ler)e bir event\/olay g\u00f6ndermekte ve bu olaya kar\u015f\u0131 di\u011fer bile\u015fenler tepki vermektedirler. Bizler bu i\u00e7eri\u011fimizde bir bile\u015fen taraf\u0131ndan yay\u0131nlanm\u0131\u015f olan bir olay\u0131n di\u011fer bile\u015fenler taraf\u0131ndan t\u00fcrl\u00fc sebeplerden dolay\u0131 birden fazla kez i\u015flenmesi durumunu ifade eden idempotent kavram\u0131n\u0131 ele al\u0131yor olacak ve bu durumun yaz\u0131l\u0131m s\u00fcrecinde yaratabilece\u011fi handikaplarla birlikte, bu duruma nas\u0131l \u00f6nlem al\u0131nabilece\u011fi \u00fczerine isti\u015farede bulunuyor olaca\u011f\u0131z. O halde buyurun ba\u015flayal\u0131m&#8230;<\/p>\n<h4>Idempotent Nedir?<\/h4>\n<p>Idempotent nedir sorusuna kar\u015f\u0131n <a href=\"https:\/\/www.gencayyildiz.com\/blog\/outbox-design-pattern-nedir-nasil-uygulanir-inbox-pattern-esliginde\/\" rel=\"noopener\" target=\"_blank\">outbox pattern<\/a>&#8216;\u0131 ele ald\u0131\u011f\u0131m\u0131z makalemizdeki konuya dair a\u00e7\u0131klamay\u0131 buraya al\u0131nt\u0131layarak cevap vermeye \u00e7al\u0131\u015fal\u0131m.<\/p>\n<blockquote><p><em style=\"color:orange;\">&#8230;matematik ve bilgisayar bilimlerinde kullan\u0131lan ve ilk i\u015flem haricinde sonraki t\u00fcm i\u015flemler i\u00e7in etkisi s\u00f6z konusu olmayan ve sonucu de\u011fi\u015ftirmeden uygulanabilen bir \u00f6zelli\u011fi ifade eden terminolojik bir terimdir. Matematiksel olarak <code style=\"color:green;\">f(f(x)) = f(x)<\/code> \u015feklinde form\u00fcl\u00fcze edilir<\/p>\n<p>Idempotent&#8217;e matematiksel \u00f6rnek olarak <u>mutlak de\u011feri<\/u> verebiliriz. Nihayetinde mutlak de\u011ferin amac\u0131 bir say\u0131n\u0131n s\u0131f\u0131ra olan uzakl\u0131\u011f\u0131n\u0131 \u00f6l\u00e7mek oldu\u011fu i\u00e7in <span style=\"font-size:12px;\">|n|<\/span> ile <span style=\"font-size:12px;\">|-n|<\/span> i\u015flemlerini ne kadar de\u011ferlendirirsek de\u011ferlendirelim, bu iki \u00f6l\u00e7\u00fcmde sonu\u00e7 a\u00e7\u0131s\u0131ndan herhangi bir fark hi\u00e7bir zaman s\u00f6z konusu olmayacakt\u0131r.<\/p>\n<p>Idempotent kavram\u0131na biz yaz\u0131l\u0131mc\u0131lar\u0131n anlayaca\u011f\u0131 dilden daha farkl\u0131 \u00f6rnekler verebilmemiz a\u00e7\u0131s\u0131ndan rest mimarisi \u00fczerinden de bir metafor ger\u00e7ekle\u015ftirebiliriz. Rest mimarisinde; <code>get<\/code>, <code>put<\/code> ve <code>delete<\/code> action&#8217;lar\u0131 idempotent iken, <code>post<\/code> metodu idempotent de\u011fildir! \u00c7\u00fcnk\u00fc <code>get<\/code>, <code>put<\/code> ve <code>delete<\/code> her ne kadar tekrarl\u0131 tetiklenirse tetiklensinler yapt\u0131klar\u0131 ilk i\u015flemin d\u0131\u015f\u0131nda ekstradan sonu\u00e7 \u00fcretemezler. Yani \u00f6rnek olarak, &#8216;3&#8217; id de\u011ferine sahip bir kullan\u0131c\u0131 silmek(delete) istiyorsan\u0131z e\u011fer bunu ilk istekte ger\u00e7ekle\u015ftirir, sonraki isteklerde ise &#8216;3&#8217; id de\u011ferine kar\u015f\u0131l\u0131k bir kullan\u0131c\u0131 olmayaca\u011f\u0131ndan dolay\u0131 ekstradan bir sonu\u00e7 \u00fcretecek i\u015flem ger\u00e7ekle\u015ftiremezsiniz. Veya <code>update products set name='abc'<\/code> sorgusunu ilk \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131n\u0131zda t\u00fcm \u00fcr\u00fcnlerin ad\u0131 &#8216;abc&#8217; olacak sonraki tetiklemelerde ise bu sorgu bir de\u011fi\u015fikli\u011fe yol a\u00e7mayacakt\u0131r. \u0130\u015fte bundan dolay\u0131 bu \u00fc\u00e7\u00fc idempotent \u00f6zellik sergilemektedir. Amma vel\u00e2kin, ad\u0131 &#8216;Hilmi&#8217; olan bir kullan\u0131c\u0131y\u0131 eklemek(post) isterseniz her istek g\u00f6nderdi\u011finizde ad\u0131 &#8216;Hilmi&#8217; olan bir kullan\u0131c\u0131 eklenecektir. Bu da sonucu etkileyecektir. \u00c7\u00fcnk\u00fc ilk istekte ad\u0131 &#8216;Hilmi&#8217; olan kullan\u0131c\u0131 say\u0131s\u0131 n iken, be\u015finci istekte n + 5 olacakt\u0131r. Haliyle <code>post<\/code> action&#8217;\u0131 netice itibariyle veritaban\u0131 \u00fczerinde i\u015flemden \u00f6nceki son hale nazaran de\u011fi\u015fiklik\/fark meydana getirece\u011fi i\u00e7in idempotent \u00f6zellik g\u00f6stermeyen bir fonksiyondur.<\/p>\n<p>Onca \u00f6rne\u011fin yan\u0131nda bir de g\u00fcnl\u00fck hayattan bir misalde bulunal\u0131m isterim. Diyelim ki X bankas\u0131n\u0131n bankamati\u011fine gittiniz ve bakiyenizi g\u00f6rmek istediniz. \u0130\u015fte bu i\u015flem bir idempotent i\u015flemdir. Nihayetinde bankamatik \u00fczerinden hesab\u0131n\u0131zdaki bakiyeyi g\u00f6rme i\u015flemini ne kadar yaparsan\u0131z yap\u0131n sonu\u00e7 de\u011fi\u015fmeyecektir. Lakin ayn\u0131 hesap \u00fczerinden para \u00e7ekme ya da para yat\u0131rma i\u015flemi yapman\u0131z idempotent olmayan bir i\u015flemdir. \u00c7\u00fcnk\u00fc yap\u0131lan her bir i\u015flem neticesinde bakiye de\u011feri de\u011fi\u015fecektir&#8230;<\/em><\/p><\/blockquote>\n<p>Yukar\u0131da yapt\u0131\u011f\u0131m\u0131z al\u0131nt\u0131n\u0131n idempotent kavram\u0131 \u00fczerine yeterince teorik bir k\u00fclt\u00fcr sa\u011flad\u0131\u011f\u0131n\u0131 d\u00fc\u015f\u00fcn\u00fcyorum. <\/p>\n<p>Haliyle i\u00e7eri\u011fin giri\u015f paragraf\u0131nda de\u011findi\u011fimiz <em>-yaz\u0131l\u0131m s\u00fcrecindeki idempotent-<\/em> durumunu izah etmemiz gerekirse e\u011fer; event-driven architecture gibi distributed mimarilerde, bir servis taraf\u0131ndan herhangi bir event&#8217;in birden fazla kez i\u015flenmesi durumu oldu\u011funu s\u00f6yleyebiliriz.<\/p>\n<h4>Idempotent Sorunsal\u0131 Nedir?<\/h4>\n<p>Bir event&#8217;in mahiyeti gere\u011fi yap\u0131lacak i\u015fin birden fazla kez i\u015flenmesi neticesinde uygulama verilerinde tutars\u0131zl\u0131k olu\u015fabilir ve bu durum uygulama a\u00e7\u0131s\u0131ndan genel manada istatisti\u011fi bozabilir. Misal olarak; bir kullan\u0131c\u0131n\u0131n hesab\u0131na para yat\u0131rma i\u015flemi ger\u00e7ekle\u015ftirildi\u011finde, do\u011fal olarak hesap bakiyesi artacakt\u0131r. Ancak bu i\u015flemi ger\u00e7ekle\u015ftirecek bile\u015fen; bakiye artt\u0131r\u0131ld\u0131ktan sonra t\u00fcrl\u00fc hatalardan kaynakl\u0131 kendini tekrar eder ve ayn\u0131 i\u015flemi tekrar devreye sokarsa burada hesap bakiyesinde ikinci kez art\u0131\u015f s\u00f6z konusu olacak ve istemsiz bir sonu\u00e7 ortaya \u00e7\u0131kacakt\u0131r.<\/p>\n<p>Idempotent sorunsal\u0131 ise esas\u0131nda idempotent tasar\u0131m\u0131n\u0131n uygulanmad\u0131\u011f\u0131 bir ba\u015fka deyi\u015fle non-idempotent<em>(idempotent olmayan)<\/em> olarak sistemin kurguland\u0131\u011f\u0131 durumlar\u0131 ifade eder. Yani yukar\u0131daki verilen misaldeki tasar\u0131m idempotent sorunsal\u0131na zemin olu\u015fturmaktad\u0131r. Bir servis yahut bile\u015fende, bir olay neticesinde yap\u0131lacak i\u015flem tekrar edilebilir bir \u015fekilde tasarlanm\u0131\u015fsa(yani idempotent tasar\u0131m yoksa) burada idempotent sorunsal\u0131ndan bahsedebiliriz. B\u00f6yle bir tasar\u0131m problemli, olas\u0131 hatalara ve t\u00fcrl\u00fc istatistiksel tutsars\u0131zl\u0131klara a\u00e7\u0131k bir tasar\u0131md\u0131r.<\/p>\n<h4>Idempotent Sorunsal\u0131na \u00c7\u00f6z\u00fcm<\/h4>\n<p>Bu sorunu \u00e7\u00f6zmek i\u00e7in, <em>Idempotent Consumer Pattern<\/em> kullan\u0131labilir. Bu tasar\u0131m, bir i\u015flemin birden fazla kez ger\u00e7ekle\u015ftirilmesi durumunda sonucun de\u011fi\u015fmemesini sa\u011flayacak yahut bir ba\u015fka deyi\u015fle ayn\u0131 i\u015flemi birden fazla kez y\u00fcr\u00fcrl\u00fc\u011fe koymayacak bir ilke sa\u011flamaktad\u0131r. Bu ilke sayesinde bir olaya kar\u015f\u0131n ayn\u0131 i\u015flemin tekrar tekrar olabilme ihtimali minimize edilecek ve do\u011fal olarak tutars\u0131zl\u0131k gibi yan etkiler de engellenmi\u015f olacakt\u0131r.<\/p>\n<h4>Idempotent Kavram\u0131 Sadece Event-Driven Architecture&#8217;da m\u0131 Ge\u00e7erlidir?<\/h4>\n<p>Tabi ki de hay\u0131r! Esas\u0131nda bu kavram sadece event-driven architecture i\u00e7in de\u011fil, genel olarak bilgi i\u015flem alan\u0131nda yayg\u0131n bir kavramd\u0131r. Basit aray\u00fcze sahip olan yaz\u0131l\u0131mlardan tutun, kompleks veritaban\u0131 y\u00f6netim s\u00fcre\u00e7lerinde kar\u015f\u0131m\u0131za \u00e7\u0131kabilecek bir sahaya sahiptir. T\u00fcm bunlar\u0131n yan\u0131nda distributed sistemlerde ve service-oriented architecture&#8217;da s\u0131kl\u0131kla kullan\u0131l\u0131r. Yani anlayaca\u011f\u0131n\u0131z; idempotent, yaz\u0131l\u0131m s\u00fcre\u00e7lerinde hangi mimaride olunursa olunsun fark\u0131nda olunmas\u0131 gereken ve sorunsal a\u00e7\u0131dan kritik s\u00fcre\u00e7lerde de\u011ferlendirilmesi \u015fart olan bir kavramd\u0131r.<\/p>\n<h4 style=\"color:#0E576D;\">Idempotent Consumer Pattern&#8217;\u0131n Tasar\u0131m\u0131 ve Di\u011fer Pattern&#8217;larla \u0130li\u015fkisi<\/h4>\n<p>Idempotent Consumer Pattern&#8217;\u0131n temel fikri, yukar\u0131daki sat\u0131rlarda ifade edildi\u011fi gibi bir i\u015flemin ayn\u0131 giri\u015f parametreleriyle birden \u00e7ok kez \u00e7a\u011fr\u0131lmas\u0131 durumunda yan etki olmaks\u0131z\u0131n i\u015flenmesini sa\u011flamaya dayanmaktad\u0131r. Evet&#8230; bunu ger\u00e7ekle\u015ftirmek zor olsa gerek, hele hele \u00e7al\u0131\u015f\u0131lan mimari distributed bir yap\u0131ya sahipse bunu sa\u011flayabilmek ger\u00e7ekten zor bir durum olsa gerek. \u0130\u015fte bu zor duruma Idempotent Consumer Pattern sayesinde \u00e7\u00f6z\u00fcmsel bir yakla\u015f\u0131m sergileyebiliriz.<\/p>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2023\/05\/Event-Driven-Mimaride-Yinelenen-Mesajlar-Idempotent-Sorunsali-ve-Idempotent-Consumer-Pattern.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2023\/05\/Event-Driven-Mimaride-Yinelenen-Mesajlar-Idempotent-Sorunsali-ve-Idempotent-Consumer-Pattern.png\" alt=\"Event-Driven Mimaride Yinelenen Mesajlar - Idempotent Sorunsal\u0131 ve Idempotent Consumer Pattern\" width=\"289\" height=\"414\" class=\"alignleft size-full wp-image-26325\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2023\/05\/Event-Driven-Mimaride-Yinelenen-Mesajlar-Idempotent-Sorunsali-ve-Idempotent-Consumer-Pattern.png 289w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2023\/05\/Event-Driven-Mimaride-Yinelenen-Mesajlar-Idempotent-Sorunsali-ve-Idempotent-Consumer-Pattern-209x300.png 209w\" sizes=\"auto, (max-width: 289px) 100vw, 289px\" \/><\/a>Bunu sa\u011flayabilmek i\u00e7in bir olay neticesinde i\u015flenecek mesaj\u0131n s\u00fcrece tabi tutulmas\u0131ndan \u00f6nce yandaki gibi ilgili mesaj\u0131n i\u015flenip i\u015flenmedi\u011fine dair gerekli tetkikin yap\u0131lmas\u0131 gerekmekte ve bunun i\u00e7in de i\u015flenmi\u015f mesajlar\u0131n benzersiz bir kimlik ile<em>(unique identifier)<\/em> bir veritaban\u0131nda saklanmas\u0131 gerekmektedir.<\/p>\n<p>Mesaj\u0131 g\u00f6nderen publisher bu mesaj\u0131 bir id ile ili\u015fkilendirecek ve consumer ise bu id \u00fczerinden veritaban\u0131ndan gerekli kontrolleri yap\u0131p s\u00fcreci y\u00f6netecektir. Tabi burada publisher&#8217;\u0131n <a href=\"https:\/\/www.gencayyildiz.com\/blog\/outbox-design-pattern-nedir-nasil-uygulanir-inbox-pattern-esliginde\/\" rel=\"noopener\" target=\"_blank\">outbox pattern<\/a>&#8216;\u0131 uygulamas\u0131 ve mesajlar\u0131 outbox table&#8217;a g\u00f6ndererek bir outbox publisher application arac\u0131l\u0131\u011f\u0131 ile kuyru\u011fa yani consumer&#8217;a g\u00f6ndermesi beklenebilir. Ayn\u0131 \u015fekilde consumer&#8217;\u0131nda i\u015fledi\u011fi mesajlar\u0131 <a href=\"https:\/\/www.gencayyildiz.com\/blog\/outbox-design-pattern-nedir-nasil-uygulanir-inbox-pattern-esliginde\/\" rel=\"noopener\" target=\"_blank\">inbox pattern<\/a>&#8216;\u0131 uygulayarak inbox table&#8217;da tutmas\u0131 ve buradan mesajlar\u0131n i\u015flenip i\u015flenmedi\u011fine dair gerekli kontrollerin yap\u0131lmas\u0131 beklenebilir. Burada akla a\u015fa\u011f\u0131daki soru gelebilir!<\/p>\n<blockquote><p><em>Idempotent Consumer Pattern \u0130le Outbox ve Inbox Pattern&#8217;lar ayn\u0131 amaca m\u0131 hizmet ediyorlar?<\/em><\/p><\/blockquote>\n<p>Dikkat ederseniz konumuz olan idempotent consumer pattern, outbox ve inbox pattern&#8217;larla kurgusal olarak bir benzerlik ili\u015fkisine sahiptir. Ama as\u0131l dikkat edilmesi gereken nokta \u015fudur ki, bu pattern&#8217;lar her ne kadar birbirlerine benzerlik g\u00f6sterseler de aralar\u0131nda odakland\u0131klar\u0131 sorunlar a\u00e7\u0131s\u0131ndan farkl\u0131l\u0131klar vard\u0131r.<\/p>\n<p>\u0130sterseniz bu \u00fc\u00e7 pattern aras\u0131ndaki benzerlik ili\u015fkisini ele alarak devam edelim.<\/p>\n<p><strong>Benzerlikler<\/strong><\/p>\n<ol>\n<li><em>G\u00fcvenilir Mesaj \u0130letimi<\/em><br \/>\nOutbox Pattern ile Idempotent Consumer Pattern; gaye olarak i\u015flenen olaylar\u0131n veya mesajlar\u0131n tekrar tekrar i\u015flenmesini engelleyerek sistemdeki tutarl\u0131l\u0131\u011f\u0131 korumak amac\u0131yla g\u00fcvenilir bir mesaj iletimini ama\u00e7lamaktad\u0131rlar.\n<\/li>\n<li><em>Durum Takibi<\/em><br \/>\nInbox Pattern ile benzer \u015fekilde Idempotent Consumer Pattern da i\u015flenen olaylar\u0131 veya mesajlar\u0131 takip eder. Her ikisi de i\u015flenen olaylar\u0131n kimliklerini kaydederek, ayn\u0131 olay\u0131n veya mesaj\u0131n tekrar olacak \u015fekilde i\u015flenmesini engeller.\n<\/li>\n<li><em>Veri Tutarl\u0131l\u0131\u011f\u0131<\/em><br \/>\nHer \u00fc\u00e7 pattern&#8217;da, veri tutarl\u0131l\u0131\u011f\u0131n\u0131 sa\u011flamak i\u00e7in kullan\u0131l\u0131r. Outbox ile Idempotent Consumer Pattern, tekrarlanabilirlikle ilgili sorunlar\u0131 ele alarak veri tutarl\u0131l\u0131\u011f\u0131n\u0131 korurken, Inbox Pattern ise gelen mesajlar\u0131n i\u015flenme durumunu takip ederek veri tutarl\u0131l\u0131\u011f\u0131n\u0131 sa\u011flar.\n<\/li>\n<\/ol>\n<p>\u015eimdi de odakland\u0131klar\u0131 sorunlar\u0131 ele alarak aralar\u0131ndaki farkl\u0131l\u0131klar\u0131 masaya yat\u0131ral\u0131m.<\/p>\n<p><strong>Odakland\u0131klar\u0131 Sorunlar<\/strong><\/p>\n<ul>\n<li><em>Idempotent Consumer Pattern<\/em><br \/>\n\u0130\u015flenen olaylar\u0131n veya mesajlar\u0131n tekrar tekrar i\u015flenmesini engelleyerek veri b\u00fct\u00fcnl\u00fc\u011f\u00fcn\u00fc ve i\u015flem tekrarlanabilirli\u011fini sa\u011flamaya odaklan\u0131r.\n<\/li>\n<li><em>Outbox Pattern<\/em><br \/>\nBir servis yahut bile\u015fen taraf\u0131ndan d\u0131\u015f sistemlere g\u00fcvenilir bir \u015fekilde mesaj iletimini hedefler.\n<\/li>\n<li><em>Inbox Pattern<\/em><br \/>\nGelen mesajlar\u0131n g\u00fcvenilir bir \u015fekilde i\u015flenmesini ve i\u015flenme durumunun takip edilmesini sa\u011flayarak distributed sistemlerde veri b\u00fct\u00fcnl\u00fc\u011f\u00fcn\u00fc korumaya odaklan\u0131r.\n<\/li>\n<\/ul>\n<p>Haliyle buradan anl\u0131yoruz ki; idempotent consumer pattern, outbox ve inbox pattern&#8217;lar ile benzerlik g\u00f6stermekte ve hatta genellikle distributed sistemlerde birlikte kullan\u0131lmaktad\u0131r.<\/p>\n<h4 style=\"color:#0E576D;\">Idempotent Consumer Pattern&#8217;\u0131n Uygulanmas\u0131<\/h4>\n<p>\u015eimdi burada pratiksel olarak idempotent consumer pattern&#8217;\u0131 basit d\u00fczeyde \u00f6rneklendiriyor olaca\u011f\u0131z. Tabi bu \u00f6rneklendirmede, outbox ve inbox pattern&#8217;lar\u0131na dair bir detay bar\u0131nd\u0131rmayacak ve direkt olarak sade bir \u015fekilde konuyu hedef alaca\u011f\u0131z. <em style=\"font-size:12px;\">(ki bilmelisiniz ki; yukar\u0131daki sat\u0131rlarda da anlat\u0131lmaya \u00e7al\u0131\u015f\u0131ld\u0131\u011f\u0131 gibi, bir tasar\u0131mda idempotent ilkesi en do\u011fru \u015fekilde outbox ve inbox pattern&#8217;lar\u0131 e\u015fli\u011finde uygulanabilir, bundan dolay\u0131 sizler ger\u00e7ek \u00e7al\u0131\u015fmalar\u0131n\u0131za bu hassasiyetle yakla\u015f\u0131m sergilemelisiniz)<\/em><\/p>\n<p>Idempotent olarak tasarlanacak mimaride mesajlar\u0131n i\u015flenip i\u015flenmedi\u011fini takip edebilmek i\u00e7in bir veritaban\u0131na ihtiyac\u0131m\u0131z olaca\u011f\u0131ndan bahsetmi\u015ftik. Haliyle bu i\u015flemi a\u015fa\u011f\u0131daki gibi bir tablo \u00fczerinden y\u00fcr\u00fctebiliriz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nCREATE TABLE &#x5B;dbo].&#x5B;Idempotent_Event]\r\n(\r\n  &#x5B;OccuredOn] &#x5B;datetime2](7) NOT NULL,\r\n  &#x5B;ProcessedDate] &#x5B;datetime2](7) NULL,\r\n  &#x5B;Type] &#x5B;nvarchar](max) NOT NULL,\r\n  &#x5B;IdempotentToken] &#x5B;uniqueidentifier] NOT NULL\r\n)\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki tablo yap\u0131s\u0131na dikkat ederseniz; ilgili mesaj\u0131n hangi tarihte olu\u015fturuldu\u011fu(OccuredOn) ve i\u015flendi\u011fi(ProcessedDate), hangi event&#8217;e kar\u015f\u0131l\u0131k geldi\u011fi(Type) ve benzersiz olarak hangi idempotent id&#8217;sine sahip oldu\u011fu(IdempotentToken) bilgileri tutulmaktad\u0131r. Tabi bu bilgilerin yan\u0131nda isterseniz outbox pattern&#8217;da oldu\u011fu gibi &#8216;Payload&#8217; kolonunda ilgili mesaj\u0131n\/event&#8217;in i\u00e7eri\u011fini de depolayabilirsiniz.<\/p>\n<p>Gelen mesajlar\u0131n consumer taraf\u0131nda handle edilmeden \u00f6nce i\u015flenip i\u015flenmedi\u011fini ise a\u015fa\u011f\u0131daki gibi check edebiliriz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class OrderCreatedEventConsumer : IConsumer&lt;OrderCreatedEvent&gt;\r\n    {\r\n        public async Task Consume(ConsumeContext&lt;OrderCreatedEvent&gt; context)\r\n        {\r\n            ApplicationDbContext dbContext = new();\r\n            if (await dbContext.IdempotentEvents.AnyAsync(idempotent =&gt; idempotent.IdempotentToken == context.Message.IdempotentToken))\r\n                return;\r\n\r\n            \/\/Handling...\r\n            \/\/Handling...\r\n            \/\/Handling...\r\n            Console.WriteLine($&quot;{JsonSerializer.Serialize(context.Message)}&quot;);\r\n\r\n            await dbContext.IdempotentEvents.AddAsync(new()\r\n            {\r\n                IdempotentToken = context.Message.IdempotentToken,\r\n                OccuredOn = DateTime.UtcNow,\r\n                ProcessedDate = DateTime.UtcNow,\r\n                Type = nameof(OrderCreatedEvent)\r\n            });\r\n            await dbContext.SaveChangesAsync();\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer; ilgili tabloda idempotent token&#8217;a kar\u015f\u0131l\u0131k bir kay\u0131t varsa e\u011fer bu mesaj\u0131n \u00f6nceden i\u015flendi\u011fini anlay\u0131p return ediyoruz, kay\u0131t yoksa da mesaj\u0131n handle edilip ard\u0131ndan i\u015flendi\u011fine dair bilgi tutabilmek i\u00e7in tabloya eklendi\u011fini g\u00f6r\u00fcyoruz. B\u00f6ylece bir i\u015fin tekrarl\u0131 olarak i\u015flenmesinin \u00f6n\u00fcne ge\u00e7mi\u015f oluyoruz.<\/p>\n<p>Burada &#8216;<em><strong>la hoca, mesaj handle edildikten sonra veritaban\u0131na eklenirken bir hata meydana gelirse napcaz?<\/strong><\/em>&#8216; \u015feklinde bir ihtimale nazaran akl\u0131n\u0131zda suallerin olu\u015ftu\u011funu sezer gibiyim&#8230; Evet, hakl\u0131s\u0131n\u0131z. E\u011fer ki mesaj handle edildikten sonra tam da veritaban\u0131na bu mesaj\u0131n handle edildi\u011fine dair kay\u0131t atarken t\u00fcrl\u00fc sebeplerden dolay\u0131 hata al\u0131n\u0131rsa yine tutars\u0131zl\u0131\u011fa mahal verebilecek bir durumla kar\u015f\u0131la\u015f\u0131lm\u0131\u015f olunacakt\u0131r. Bu durumu engelleyebilmek i\u00e7in ise hata kontrol\u00fc yapmal\u0131 ve hata meydana geldi\u011fi taktirde handle s\u00fcrecinde yap\u0131lan i\u015flemlerin hepsi geri al\u0131nmal\u0131d\u0131r.<\/p>\n<p>\u015e\u00f6yle ki;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class OrderCreatedEventConsumer : IConsumer&lt;OrderCreatedEvent&gt;\r\n    {\r\n        public async Task Consume(ConsumeContext&lt;OrderCreatedEvent&gt; context)\r\n        {\r\n            try\r\n            {\r\n                ApplicationDbContext dbContext = new();\r\n                if (await dbContext.IdempotentEvents.AnyAsync(idempotent =&gt; idempotent.IdempotentToken == context.Message.IdempotentToken))\r\n                    return;\r\n\r\n                \/\/Handling...\r\n                \/\/Handling...\r\n                \/\/Handling...\r\n                Console.WriteLine($&quot;{JsonSerializer.Serialize(context.Message)}&quot;);\r\n\r\n                await dbContext.IdempotentEvents.AddAsync(new()\r\n                {\r\n                    IdempotentToken = context.Message.IdempotentToken,\r\n                    OccuredOn = DateTime.UtcNow,\r\n                    ProcessedDate = DateTime.UtcNow,\r\n                    Type = nameof(OrderCreatedEvent)\r\n                });\r\n                await dbContext.SaveChangesAsync();\r\n            }\r\n            catch\r\n            {\r\n                \/\/Rollback Handling\r\n                \/\/or\r\n                \/\/Compensable Transactions\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funa g\u00f6z atarsan\u0131z e\u011fer veritaban\u0131nda idempotent token&#8217;a kar\u015f\u0131l\u0131k bir mesaj yoksa e\u011fer gerekli handling operasyonu ger\u00e7ekle\u015ftirilmekte ve mesaj\u0131n i\u015flendi\u011fine dair veritaban\u0131na idempotent token ile ili\u015fkili kay\u0131t at\u0131lmaktad\u0131r. Yok e\u011fer bu s\u00fcre\u00e7te bir hata meydana gelirse e\u011fer yap\u0131lan t\u00fcm i\u015flemler geri al\u0131nmaktad\u0131r.<\/p>\n<blockquote><p><em style=\"color:orange;\">Idempotent Consumer Pattern&#8217;\u0131 salt bir \u015fekilde uygulan\u0131yorsa e\u011fer buna <u>Lazy Idempotent Consumer<\/u> yok e\u011fer rollback handling yahut compensable transaction tasar\u0131m\u0131 g\u00f6z \u00f6n\u00fcne al\u0131n\u0131yorsa e\u011fer buna da <u>Eager Idempotent Consumer<\/u> ad\u0131 verilmektedir.<\/em><\/p><\/blockquote>\n<p>Nihai olarak;<br \/>\nIdempotent sorunsal\u0131na kar\u015f\u0131 g\u00f6stermi\u015f oldu\u011fumuz davran\u0131\u015f her ne kadar kritik bir tutum olsa da baz\u0131 i\u015flemlerin do\u011fal olarak idempotent oldu\u011funu ve bu i\u015flemlerde bu pattern&#8217;\u0131n uygulanmas\u0131n\u0131n gereksiz bir maliyete sebebiyet verece\u011fini akl\u0131n\u0131zdan \u00e7\u0131karmaman\u0131z gerekmektedir. Ayr\u0131ca yaz\u0131 s\u00fcrecinde s\u00fcrekli ifade etti\u011fimiz gibi her ne kadar bu i\u00e7eri\u011fimizde tek ba\u015f\u0131na idempotent consumer pattern&#8217;a odaklanm\u0131\u015f olsak da distributed sistemlerde, outbox ve inbox pattern&#8217;lar e\u015fli\u011finde idempotent mant\u0131\u011f\u0131n\u0131 uygulamak b\u00fct\u00fcnsel a\u00e7\u0131dan daha anlaml\u0131 olacak ve hatta onlar olmaks\u0131z\u0131n idempotent consumer pattern&#8217;\u0131n da bir anlam\u0131 kalmayacakt\u0131r diyebiliriz.<\/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<p>Not : \u00d6rnek projeye a\u015fa\u011f\u0131daki github adresinden eri\u015febilirsiniz.<br \/>\n<a href=\"https:\/\/github.com\/gncyyldz\/Idempotent.Consumer.Pattern.Example\" rel=\"noopener\" target=\"_blank\">https:\/\/github.com\/gncyyldz\/Idempotent.Consumer.Pattern.Example<\/a><\/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, Yaz\u0131l\u0131m olgusu, tabiat\u0131 gere\u011fi birbiriyle etkile\u015fim kurma mecburiyetinde olan farkl\u0131 bile\u015fenlerden meydana gelip, anatomik olarak b\u00fct\u00fcnl\u00fck arz eden bir olgudur. Bu b\u00fct\u00fcnl\u00fc\u011f\u00fcn i\u00e7erisindeki bile\u015fenler aras\u0131ndaki etkile\u015fimi modelleyebilmemizi sa\u011flayan t\u00fcrl\u00fc yakla\u015f\u0131mlar mevcuttur ve bu&#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":3014,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4446,4754,2739,12,153],"tags":[750,4795,4792,2433,4791,4789,4788,4793,4790,4794],"class_list":["post-26319","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-6","category-net-7","category-net-core","category-c-sharp-c","category-design-pattern","tag-design-pattern","tag-eager-idempotent-consumer","tag-eda","tag-event-driven","tag-event-driven-architecture","tag-event-driven-idempotent","tag-event-driven-mimari","tag-idempotent-consumer-pattern","tag-idempotent-sorunsali","tag-lazy-idempotent-consumer"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26319","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=26319"}],"version-history":[{"count":9,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26319\/revisions"}],"predecessor-version":[{"id":26329,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26319\/revisions\/26329"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/3014"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=26319"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=26319"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=26319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}