[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fBW2Vi5GDFUjN7cIAdN0gJ0Wg01QOIMwFAgtovbfhVRo":3},{"data":4,"related":96},{"id":5,"title":6,"slug":7,"excerpt":8,"cover":9,"category":11,"author":14,"track":20,"level":23,"reading_minutes":26,"is_featured":27,"published_at":28,"updated_at":28,"body":29,"toc":30,"tags":62,"faqs":77,"related_services":90,"comments_enabled":94,"meta_title":19,"meta_description":95,"canonical_url":19,"noindex":27,"is_live":94},3,"قطع شدن WebSocket در HAProxy هر ۵۰ ثانیه؛ علت و راه‌حل","haproxy-websocket-timeout-50s","اگر WebSocket یا SSE پشت HAProxy هر ۵۰ ثانیه قطع می‌شود، مقصر تایماوت‌های پیش‌فرض فایل نمونه است. در این مقاله علت ریشه‌ای و پیکربندی درست timeout tunnel را بررسی می‌کنیم.",{"url":10,"alt":6},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002F26b583b4-d805-45d6-a265-a94d73b5a21d.webp",{"name":12,"slug":13},"Linux و مدیریت سرور","linux",{"name":15,"slug":16,"role":17,"bio":18,"linkedin_url":19,"avatar_url":19},"تحریریه کلودیکپ","cloudicap-editorial","تیم محتوای کلودیکپ","تیم فنی و محتوای کلودیکپ؛ مهندسانی که هر روز با DevOps، Kubernetes و زیرساخت ابری کار می‌کنند و تجربه‌هایشان را اینجا می‌نویسند.",null,{"value":21,"label":22},"engineers","مهندسان",{"value":24,"label":25},"intermediate","متوسط",7,false,"2026-10-07T07:57:29+00:00","\u003Ch2 id=\"شرح-مسئله\">شرح مسئله\u003C\u002Fh2>\n\u003Cp>سرویسی با WebSocket (چت، نوتیفیکیشن، داشبورد زنده) یا SSE را پشت HAProxy گذاشته‌اید. همه‌چیز در ابتدا درست کار می‌کند، اما بعد از چند دقیقه همه‌ی کلاینت‌ها تقریباً هم‌زمان دوباره وصل می‌شوند. نشانه‌های کلاسیک این مشکل:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>در کنسول مرورگر، اتصال با close code \u003Ccode>1006\u003C\u002Fcode> (بسته‌شدن غیرعادی) قطع می‌شود و فاصله‌ی بین قطع و وصل مجدد تقریباً ثابت است؛ چیزی حدود ۵۰ ثانیه، آن هم دقیقاً وقتی هیچ داده‌ای رد و بدل نمی‌شود.\u003C\u002Fli>\n\u003Cli>در لاگ HAProxy در حالت \u003Ccode>mode http\u003C\u002Fcode> خطی شبیه این می‌بینید (فقط بخش مهم آن آورده شده):\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode class=\"language-bash\">haproxy[2137]: 10.20.30.40:52184 [21\u002FMay\u002F2025:10:11:13.001] fe_web be_ws\u002Fapp1 0\u002F0\u002F0\u002F50213\u002F50219 101 0 - - cD-- 12\u002F12\u002F0\u002F0\u002F0 0\u002F0\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>کد وضعیت \u003Ccode>101\u003C\u002Fcode> یعنی ارتقای پروتکل انجام شده و اتصال WebSocket برقرار بوده است؛ اما مقدار تایمرها حدود ۵۰٬۰۰۰ میلی‌ثانیه است، یعنی نشست دقیقاً بعد از ۵۰ ثانیه خاتمه یافته. مهم‌تر از همه، کد خاتمه \u003Ccode>cD--\u003C\u002Fcode> است: تایم‌اوت کلاینت در فاز انتقال داده.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>درخواست‌های HTTP طولانی (long-polling یا پاسخ‌های کند) با کد \u003Ccode>504\u003C\u002Fcode> برمی‌گردند و در لاگ کد خاتمه \u003Ccode>sD--\u003C\u002Fcode> ثبت می‌شود.\u003C\u002Fli>\n\u003Cli>در حالت \u003Ccode>mode tcp\u003C\u002Fcode> هیچ کد وضعیتی ثبت نمی‌شود و اتصال بدون هیچ پیام مشخصی ریست می‌شود؛ همین موضوع عیب‌یابی را سخت‌تر می‌کند.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Ch2 id=\"علت-ریشه‌ای\">علت ریشه‌ای\u003C\u002Fh2>\n\u003Cp>مقصر، همان چند خطی است که تقریباً همه از فایل نمونه‌ی \u003Ccode>\u002Fetc\u002Fhaproxy\u002Fhaproxy.cfg\u003C\u002Fcode> کپی می‌کنند: \u003Ccode>timeout client 50s\u003C\u002Fcode> و \u003Ccode>timeout server 50s\u003C\u002Fcode>. این تایم‌اوت‌ها مطلق (absolute) نیستند؛ تایم‌اوت بی‌کاری (inactivity) هستند و با هر بار انتقال داده در هر جهت ریست می‌شوند.\u003C\u002Fp>\n\u003Cp>مشکل اینجاست که یک اتصال WebSocket معمولاً بیشتر وقت‌ها بی‌کار است. کاربر در چت چیزی تایپ نمی‌کند، داشبورد زنده دوباره داده نمی‌فرستد و هیچ بسته‌ای رد و بدل نمی‌شود. بعد از ۵۰ ثانیه سکوت، HAProxy اتصال را می‌بندد؛ بدون هیچ خطای سمت سرور اپلیکیشن، چون خودش این کار را کرده است.\u003C\u002Fp>\n\u003Cp>وقتی سرور پاسخ \u003Ccode>101 Switching Protocols\u003C\u002Fcode> می‌دهد و اتصال به یک تونل دوسویه تبدیل می‌شود، HAProxy از \u003Ccode>timeout tunnel\u003C\u002Fcode> استفاده می‌کند. اما اگر این تایم‌اوت در پیکربندی تعریف نشده باشد، HAProxy به همان \u003Ccode>timeout client\u003C\u002Fcode> و \u003Ccode>timeout server\u003C\u002Fcode> برمی‌گردد. نتیجه دقیقاً همان چیزی است که در لاگ دیدید: هر ۵۰ ثانیه سکوت، یک اتصال بسته.\u003C\u002Fp>\n\u003Cp>برای SSE ماجرا کمی متفاوت است: SSE یک تونل نیست، بلکه یک پاسخ HTTP طولانی است که سرور باز نگه می‌دارد؛ پس \u003Ccode>timeout server\u003C\u002Fcode> مستقیماً روی آن اعمال می‌شود. \u003Ccode>timeout http-keep-alive\u003C\u002Fcode> هم فقط برای فاصله‌ی بین دو درخواست روی یک اتصال keep-alive است و اینجا نقش اصلی را ندارد.\u003C\u002Fp>\n\n\u003Ch2 id=\"راه‌حل-گام‌به‌گام\">راه‌حل گام‌به‌گام\u003C\u002Fh2>\n\u003Ch3 id=\"۱-تأیید-تشخیص-از-روی-لاگ-و-سوکت-مدیریتی\">۱. تأیید تشخیص از روی لاگ و سوکت مدیریتی\u003C\u002Fh3>\n\u003Cp>اول مطمئن شوید واقعاً تایم‌اوت عامل ماجراست، نه کرش اپلیکیشن یا ری‌استارت پادها:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\"># کدهای خاتمه مربوط به تایم‌اوت\nsudo grep -E \"cD--|sD--\" \u002Fvar\u002Flog\u002Fhaproxy.log | tail -20\n\n# آمار لحظه‌ای backendها از سوکت مدیریتی\necho \"show stat\" | sudo socat stdio \u002Fvar\u002Frun\u002Fhaproxy.sock | awk -F, 'NR==1 || $2==\"app1\" || $2==\"app2\" {print $1, $2, $5, $18}'\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>اگر خطوط پر از \u003Ccode>cD--\u003C\u002Fcode> بود و ستون \u003Ccode>status\u003C\u002Fcode> سرورها \u003Ccode>UP\u003C\u002Fcode> بود، تشخیص تأیید می‌شود. اگر سوکت مدیریتی تنظیم نشده باشد، این خط را به بخش \u003Ccode>global\u003C\u002Fcode> اضافه کنید: \u003Ccode>stats socket \u002Fvar\u002Frun\u002Fhaproxy.sock mode 660 level admin\u003C\u002Fcode>.\u003C\u002Fp>\n\n\u003Ch3 id=\"۲-تعریف-درست-تایم‌اوت‌ها\">۲. تعریف درست تایم‌اوت‌ها\u003C\u002Fh3>\n\u003Cp>تایم‌اوت‌ها را به سه دسته تقسیم کنید: کوتاه برای محافظت (اتصال و دریافت درخواست)، متوسط برای نشست HTTP، و بلند برای تونل. نمونه‌ی کامل و قابل اجرا:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-ini\">global\n    log \u002Fdev\u002Flog local0\n    maxconn 20000\n    stats socket \u002Fvar\u002Frun\u002Fhaproxy.sock mode 660 level admin\n    stats timeout 30s\n\ndefaults\n    mode http\n    log global\n    option httplog\n    option dontlognull\n\n    # محافظت: کوتاه بماند تا از هدررفتن منابع جلوگیری شود\n    timeout connect 5s\n    timeout http-request 10s\n    timeout http-keep-alive 10s\n\n    # نشست HTTP: از تایم‌اوت نمونه (50s) خیلی بزرگ‌تر\n    timeout client 5m\n    timeout server 5m\n\n    # کلید ماجرا: تونل WebSocket\n    timeout tunnel 1h\n\n    retries 2\n\nfrontend fe_web\n    bind *:443 ssl crt \u002Fetc\u002Fhaproxy\u002Fcerts\u002Fexample.com.pem alpn h2,http\u002F1.1\n    default_backend be_ws\n\nbackend be_ws\n    balance roundrobin\n    server app1 10.0.1.11:8080 check\n    server app2 10.0.1.12:8080 check\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>نکته: مقدار \u003Ccode>0\u003C\u002Fcode> برای \u003Ccode>timeout tunnel\u003C\u002Fcode> یعنی بی‌نهایت. این کار مشکل را حل می‌کند اما اتصال‌های مرده تا ابد در حافظه می‌مانند و ظرفیت \u003Ccode>maxconn\u003C\u002Fcode> را می‌خورند؛ توصیه نمی‌شود. عددی مثل \u003Ccode>1h\u003C\u002Fcode> یا \u003Ccode>4h\u003C\u002Fcode> انتخاب معقولی است.\u003C\u002Fp>\n\n\u003Ch3 id=\"۳-جداسازی-ترافیک-websocket-توصیه‌شده\">۳. جداسازی ترافیک WebSocket (توصیه‌شده)\u003C\u002Fh3>\n\u003Cp>تحمیل تایم‌اوت بلند به همه‌ی ترافیک ایده‌ی خوبی نیست؛ چون مهاجم می‌تواند با بازکردن اتصال‌های HTTP بی‌کار، منابع را اشغال کند. WebSocket را روی یک backend جدا ببرید:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-ini\">frontend fe_web\n    bind *:443 ssl crt \u002Fetc\u002Fhaproxy\u002Fcerts\u002Fexample.com.pem alpn h2,http\u002F1.1\n    acl is_ws path_beg \u002Fws\n    use_backend be_ws if is_ws\n    default_backend be_app\n\nbackend be_ws\n    balance roundrobin\n    timeout tunnel 4h\n    server app1 10.0.1.11:8080 check\n    server app2 10.0.1.12:8080 check\n\nbackend be_app\n    balance roundrobin\n    timeout server 30s\n    server app1 10.0.1.11:8080 check\n    server app2 10.0.1.12:8080 check\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3 id=\"۴-اعتبارسنجی-و-reload-بدون-قطعی\">۴. اعتبارسنجی و reload بدون قطعی\u003C\u002Fh3>\n\u003Cp>قبل از هر reload، پیکربندی را چک کنید:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">sudo haproxy -c -f \u002Fetc\u002Fhaproxy\u002Fhaproxy.cfg\n# خروجی مورد انتظار: Configuration file is valid\n\nsudo systemctl reload haproxy\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>اگر خودتان reload را به‌صورت دستی مدیریت می‌کنید، از \u003Ccode>-sf\u003C\u002Fcode> استفاده کنید تا پروسه‌ی قبلی اتصال‌های فعال را تا پایان کارشان نگه دارد؛ برای WebSocket این تفاوت بزرگی می‌کند:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">sudo haproxy -Ws -f \u002Fetc\u002Fhaproxy\u002Fhaproxy.cfg -p \u002Frun\u002Fhaproxy.pid -sf $(cat \u002Frun\u002Fhaproxy.pid)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3 id=\"۵-سقف-اتصال-و-file-descriptor\">۵. سقف اتصال و file descriptor\u003C\u002Fh3>\n\u003Cp>هر اتصال WebSocket یک slot از \u003Ccode>maxconn\u003C\u002Fcode> و یک file descriptor مصرف می‌کند. اگر تعداد کاربران زیاد است، هم \u003Ccode>maxconn\u003C\u002Fcode> را بالا ببرید و هم سقف توصیف‌گر فایل سرویس را:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">echo \"show info\" | sudo socat stdio \u002Fvar\u002Frun\u002Fhaproxy.sock | grep -E \"Maxconn|CurrConns|Maxsock\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>برای systemd یک override بسازید (\u003Ccode>\u002Fetc\u002Fsystemd\u002Fsystem\u002Fhaproxy.service.d\u002Flimits.conf\u003C\u002Fcode>):\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-ini\">[Service]\nLimitNOFILE=65536\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>این تغییر به restart نیاز دارد، پس در پنجره‌ی نگهداری انجامش دهید.\u003C\u002Fp>\n\n\u003Ch2 id=\"چطور-مطمئن-شویم-مشکل-حل-شده-است\">چطور مطمئن شویم مشکل حل شده است\u003C\u002Fh2>\n\u003Col>\n\u003Cli>تست اتصال بی‌کار با \u003Ccode>wscat\u003C\u002Fcode>. هدف این است که عمداً بیش از ۵۰ ثانیه هیچ داده‌ای نفرستید:\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode class=\"language-bash\">npm install -g wscat\n\ndate -Ins\nwscat -c wss:\u002F\u002Fexample.com\u002Fws\n# هیچ ورودی‌ای تایپ نکنید و چند دقیقه صبر کنید\ndate -Ins\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>در حالت سالم، اتصال تا وقتی خودتان Ctrl+C نزنید باز می‌ماند. اگر باز هم حدود ۵۰ ثانیه قطع شد، پیکربندی جدید لود نشده یا یک پروکسی دیگر در مسیر (مثل nginx با \u003Ccode>proxy_read_timeout\u003C\u002Fcode>) دارد اتصال را می‌بندد.\u003C\u002Fp>\n\u003Col start=\"2\">\n\u003Cli>برای SSE، یک درخواست خام بفرستید و ببینید پاسخ بعد از ۵۰ ثانیه قطع نمی‌شود:\n\u003Cpre>\u003Ccode class=\"language-bash\">curl -N -H \"Accept: text\u002Fevent-stream\" https:\u002F\u002Fexample.com\u002Fevents\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fli>\n\u003Cli>لاگ را دوباره پایش کنید؛ در نشست‌های عادی دیگر نباید \u003Ccode>cD--\u003C\u002Fcode> یا \u003Ccode>sD--\u003C\u002Fcode> ببینید:\n\u003Cpre>\u003Ccode class=\"language-bash\">sudo tail -f \u002Fvar\u002Flog\u002Fhaproxy.log | grep -E \"cD--|sD--\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fli>\n\u003Cli>با \u003Ccode>show stat\u003C\u002Fcode> مقدار \u003Ccode>scur\u003C\u002Fcode> روی \u003Ccode>be_ws\u003C\u002Fcode> را با تعداد کلاینت‌های واقعی مقایسه کنید؛ این عدد باید با گذشت زمان ثابت بماند و مدام صفر نشود.\u003C\u002Fli>\n\u003Cli>اگر می‌خواهید مطمئن شوید پیکربندی جدید فعال است، شناسه‌ی پروسه و uptime را از سوکت بخوانید: \u003Ccode>show info\u003C\u002Fcode> بعد از reload باید \u003Ccode>Pid\u003C\u002Fcode> تازه و \u003Ccode>Uptime\u003C\u002Fcode> کوچک نشان دهد.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Ch2 id=\"پیشگیری-و-بهترین-روش‌ها\">پیشگیری و بهترین روش‌ها\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>تایم‌اوت‌های نمونه را کپی نکنید.\u003C\u002Fstrong> \u003Ccode>50s\u003C\u002Fcode> فقط یک مقدار نمایشی است. هر frontend و backend باید تایم‌اوت‌های صریح و متناسب با نوع ترافیک خودش داشته باشد.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>برای هر تونل، \u003Ccode>timeout tunnel\u003C\u002Fcode> بگذارید.\u003C\u002Fstrong> این تنها تایم‌اوتی است که رفتار اتصال‌های ارتقایافته را کنترل می‌کند و اگر نباشد، تایم‌اوت‌های نشست جای آن را می‌گیرند.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>ترافیک WebSocket را جدا کنید.\u003C\u002Fstrong> یک backend اختصاصی با تایم‌اوت بلند، و تایم‌اوت‌های کوتاه برای ترافیک معمولی.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>درخواست‌های keep-alive را با \u003Ccode>timeout http-keep-alive\u003C\u002Fcode> کنترل کنید، نه با بالا بردن \u003Ccode>timeout client\u003C\u002Fcode>.\u003C\u002Fstrong> بالا بردن بی‌دلیل \u003Ccode>timeout client\u003C\u002Fcode> باعث تجمع اتصال‌های نیمه‌باز می‌شود.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Heartbeat سطح اپلیکیشن اضافه کنید.\u003C\u002Fstrong> یک پیام ping هر ۲۰ تا ۳۰ ثانیه، هم اتصال‌های مرده را در مسیرهای میانی زودتر تشخیص می‌دهد و هم به load balancerهای میانی (مثل ALB) اجازه نمی‌دهد اتصال را بی‌کار ببینند.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>تایم‌اوت‌های بقیه‌ی لایه‌ها را هم هم‌راستا کنید.\u003C\u002Fstrong> اگر nginx یا یک Ingress جلوی HAProxy است، \u003Ccode>proxy_read_timeout\u003C\u002Fcode> و \u003Ccode>proxy_send_timeout\u003C\u002Fcode> آن هم باید از بازه‌ی بیکاری WebSocket بزرگ‌تر باشد.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ca href=\"\u002Fservices\u002Fmonitoring\">مانیتورینگ\u003C\u002Fa> را جدی بگیرید.\u003C\u002Fstrong> روی نرخ \u003Ccode>5xx\u003C\u002Fcode>، رسیدن \u003Ccode>scur\u003C\u002Fcode> به \u003Ccode>slim\u003C\u002Fcode> (سقف نشست) و پر شدن \u003Ccode>CurrConns\u003C\u002Fcode> نسبت به \u003Ccode>Maxconn\u003C\u002Fcode> هشدار تعریف کنید.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>در کلاینت، reconnect با backoff نمایی پیاده کنید.\u003C\u002Fstrong> حتی با پیکربندی درست، قطعی شبکه رخ می‌دهد؛ رفتار درست کلاینت باعث می‌شود قطعی کوتاه، به یک طوفان اتصال تبدیل نشود.\u003C\u002Fli>\n\u003C\u002Ful>",[31,35,38,41,44,47,50,53,56,59],{"id":32,"text":33,"level":34},"شرح-مسئله","شرح مسئله",2,{"id":36,"text":37,"level":34},"علت-ریشه‌ای","علت ریشه‌ای",{"id":39,"text":40,"level":34},"راه‌حل-گام‌به‌گام","راه‌حل گام‌به‌گام",{"id":42,"text":43,"level":5},"۱-تأیید-تشخیص-از-روی-لاگ-و-سوکت-مدیریتی","۱. تأیید تشخیص از روی لاگ و سوکت مدیریتی",{"id":45,"text":46,"level":5},"۲-تعریف-درست-تایم‌اوت‌ها","۲. تعریف درست تایم‌اوت‌ها",{"id":48,"text":49,"level":5},"۳-جداسازی-ترافیک-websocket-توصیه‌شده","۳. جداسازی ترافیک WebSocket (توصیه‌شده)",{"id":51,"text":52,"level":5},"۴-اعتبارسنجی-و-reload-بدون-قطعی","۴. اعتبارسنجی و reload بدون قطعی",{"id":54,"text":55,"level":5},"۵-سقف-اتصال-و-file-descriptor","۵. سقف اتصال و file descriptor",{"id":57,"text":58,"level":34},"چطور-مطمئن-شویم-مشکل-حل-شده-است","چطور مطمئن شویم مشکل حل شده است",{"id":60,"text":61,"level":34},"پیشگیری-و-بهترین-روش‌ها","پیشگیری و بهترین روش‌ها",[63,66,69,71,74],{"name":64,"slug":65},"HAProxy","haproxy",{"name":67,"slug":68},"WebSocket","websocket",{"name":70,"slug":70},"timeout",{"name":72,"slug":73},"Load Balancing","load-balancing",{"name":75,"slug":76},"Troubleshooting","troubleshooting",[78,81,84,87],{"question":79,"answer":80},"آیا timeout tunnel روی درخواست‌های HTTP معمولی هم اثر دارد؟","نه. این تایم‌اوت فقط بعد از تبدیل اتصال به یک تونل دوسویه (مثلاً بعد از پاسخ 101 برای WebSocket) اعمال می‌شود. ترافیک HTTP عادی همچنان تابع timeout client و timeout server است، مگر اینکه آن‌ها را در همان backend بازنویسی کنید.",{"question":82,"answer":83},"timeout client را زیاد کردم اما WebSocket هنوز قطع می‌شود؛ چرا؟","احتمالاً یک لایه‌ی دیگر در مسیر اتصال را می‌بندد (nginx، Ingress، فایروال سازمانی یا خود اپلیکیشن). کد خاتمه در لاگ HAProxy تعیین می‌کند مقصر کدام سمت است: cD-- یعنی HAProxy سمت کلاینت را تایم‌اوت کرده، sD-- یعنی سمت سرور. اگر هیچ‌کدام را نمی‌بینید، اتصال جای دیگری بسته شده است.",{"question":85,"answer":86},"آیا مقدار 0 برای timeout tunnel ایده‌ی خوبی است؟","خیر. مقدار 0 یعنی بی‌نهایت؛ این کار قطعی‌های ۵۰ ثانیه‌ای را از بین می‌برد اما اتصال‌های مرده هرگز آزاد نمی‌شوند و به‌سرعت ظرفیت maxconn و حافظه را اشغال می‌کنند. یک مقدار محدود مانند 1h یا 4h به همراه heartbeat سطح اپلیکیشن، انتخاب امن‌تری است.",{"question":88,"answer":89},"برای SSE هم باید timeout tunnel بگذارم؟","نه لزوماً. SSE یک تونل دوسویه نیست؛ یک پاسخ HTTP طولانی است که سرور باز نگه می‌دارد، پس timeout server روی آن اثر می‌گذارد. اگر پاسخ SSE بیشتر از timeout server باز می‌ماند، همان مقدار را در backend مربوطه بیشتر کنید.",[91,92,93],"devsecops","cloud-infrastructure","managed-devops",true,"چرا WebSocket در HAProxy هر ۵۰ ثانیه قطع می‌شود؟ علت، تنظیم درست timeout tunnel و timeout client\u002Fserver، reload بدون قطعی و روش تست.",[97,111,125],{"id":98,"title":99,"slug":100,"excerpt":101,"cover":102,"category":104,"author":107,"track":108,"level":109,"reading_minutes":26,"is_featured":27,"published_at":110,"updated_at":110},4,"حلقه بی‌پایان Jira Automation: وقتی قانون خودش را صدا می‌زند","jira-automation-infinite-loop-fix","اگر trigger و action یک قانون Jira Automation روی یک رویداد بیفتند، قانون خودش را دوباره اجرا می‌کند و issue با صدها کامنت تکراری پر می‌شود. این مقاله علت، پاک‌سازی و راه‌حل پایدار را نشان می‌دهد.",{"url":103,"alt":99},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002F696958ce-e1fa-458e-b7df-1f1a99fe6a5f.webp",{"name":105,"slug":106},"CI\u002FCD و اتوماسیون","cicd",{"name":15,"slug":16,"role":17,"avatar_url":19},{"value":21,"label":22},{"value":24,"label":25},"2026-10-07T09:28:33+00:00",{"id":34,"title":112,"slug":113,"excerpt":114,"cover":115,"category":117,"author":120,"track":121,"level":122,"reading_minutes":123,"is_featured":27,"published_at":124,"updated_at":124},"پرشدن دیسک PostgreSQL با WAL اسلات replication غیرفعال","postgresql-replication-slot-wal-disk-full","یک replication slot غیرفعال می‌تواند pg_wal را تا پر شدن کامل دیسک نگه دارد و دیتابیس را عملاً از کار بیندازد. در این مقاله ریشه‌یابی، رفع و پیشگیری از آن را گام‌به‌گام بررسی می‌کنیم.",{"url":116,"alt":112},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002F88c82e31-0162-4db1-835f-5c86fba77647.webp",{"name":118,"slug":119},"مانیتورینگ و پایداری","monitoring",{"name":15,"slug":16,"role":17,"avatar_url":19},{"value":21,"label":22},{"value":24,"label":25},6,"2026-10-06T17:39:51+00:00",{"id":126,"title":127,"slug":128,"excerpt":129,"cover":130,"category":132,"author":133,"track":134,"level":135,"reading_minutes":136,"is_featured":27,"published_at":137,"updated_at":137},1,"«idle in transaction» در PostgreSQL: قاتل خاموش autovacuum","postgres-idle-in-transaction-autovacuum-bloat","نشست‌های idle in transaction تراکنش را باز نگه می‌دارند، جلوی autovacuum را می‌گیرند و جدول‌ها را باد می‌کنند تا جایی که دیسک پر و اتصال‌ها تمام می‌شود. این مقاله تشخیص و درمان کامل آن است.",{"url":131,"alt":127},"https:\u002F\u002Fapi.cloudicap.com\u002Fmedia\u002Fposts\u002F40aa29f7-e1d0-4c30-94f6-631ea9a173a0.webp",{"name":118,"slug":119},{"name":15,"slug":16,"role":17,"avatar_url":19},{"value":21,"label":22},{"value":24,"label":25},8,"2026-10-06T17:33:36+00:00"]