<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های حمزه قائم پناه</title>
        <link>https://virgool.io/feed/@hamze</link>
        <description>مهندس نرم‌افزار و عاشق توسعه فردی - تکنیکال لید - اکس هم بنیان‌گذار و مدیرفنی و پرداکت استارتاپ کشمون</description>
        <language>fa</language>
        <pubDate>2026-04-15 09:47:55</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/223711/avatar/CciHnz.jpg?height=120&amp;width=120</url>
            <title>حمزه قائم پناه</title>
            <link>https://virgool.io/@hamze</link>
        </image>

                    <item>
                <title>نقشه راه انتخاب بین مونولیتیک یا مایکروسرویس</title>
                <link>https://virgool.io/@hamze/%D9%86%D9%82%D8%B4%D9%87-%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AA%D8%AE%D8%A7%D8%A8-%D8%A8%DB%8C%D9%86-%D9%85%D9%88%D9%86%D9%88%D9%84%DB%8C%D8%AA%DB%8C%DA%A9-%DB%8C%D8%A7-%D9%85%D8%A7%DB%8C%DA%A9%D8%B1%D9%88%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-cco9cb5iqorx</link>
                <description>معماری مونولیتیک همیشه به چند دلیل اولین انتخاب می‌تونه باشه: توسعه، تست، استقرار و رشد دادنش خیلی ساده است که این ویژگی‌ها در مراحل اولیه ایده (early-stage) خیلی مفیده.اما چطور معماری مونولیتیک می‌تونه تبدیل به جهنم بشه:پیچیدگی‌هایی که برنامه‌نویس رو پیر می‌کنه: کد بیس اونقد بزرگ بشه که دیگه واقعا نشه یک برنامه‌نویس همه‌شو به طور کامل بفهمه. اون موقع‌اس که تغییرات کند و ریسکی میشه.توسعه و استقرار کند بشه: اونقدر کدبیس بزرگ شده که، زمان توسعه و راه‌اندازی زیاد شده، در حدی که دیگه نسخه‌های جدید ماهانه بالا میان و خبری از استقرار مستمر (continuous deployment) نیست و تست‌های دستی گلوگاه (bottleneck) شدن.مشکلات رشد دادن پیش بیاد: درون یک کدبیس مونولیتیک، بین نیازهای منابع مثل CPU و RAM تداخل پیش بیاد.اطمینان به سیستم کم بشه و مدیریت خطاها سخت بشه: یک باگ توی یک بخش می‌تونه کل سیستم رو مختل کنه.قفل شدن به یک فناوری پیش میاد: اونقد کدبیس بزرگ شده که نمیشه به این سادگی‌ها فریمورک آپدیت کرد یا از تکنولوژی‌های جدید استفاده کرد.توجه داشته باشیم که Microservicef با Service Oriented Architecture متفاوته، دیتابیسش مشترکه، پروتکل ارتباطیش متفاوته و سیستم‌هایی با سایز بزرگ هستن.معایب مایکروسرویس:پیچیدگی سیستم‌های توزیع شده: Network latency, eventual consistency, debuggingچالشِ تقسیم‌بندی سیستم: ریسک تولید سیستم‌های مونولیتیکِ توزیع شده :))سربار عملیاتی: DevOps automation (orchestration, monitoring)پیچیدگی در تست: تست End-to-end سخت‌تر خواهد شد </description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sat, 20 Dec 2025 19:49:48 +0330</pubDate>
            </item>
                    <item>
                <title>چالش‌های معماری مایکروسرویس در سیستم‌های مالی با تراکنش بالا</title>
                <link>https://virgool.io/@hamze/%DA%86%D8%A7%D9%84%D8%B4-%D9%87%D8%A7%DB%8C-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-%D9%85%D8%A7%DB%8C%DA%A9%D8%B1%D9%88%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D8%AF%D8%B1-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%87%D8%A7%DB%8C-%D9%85%D8%A7%D9%84%DB%8C-%D8%A8%D8%A7-%D8%AA%D8%B1%D8%A7%DA%A9%D9%86%D8%B4-%D8%A8%D8%A7%D9%84%D8%A7-iseamyqpr5ta</link>
                <description>فکر کنین یک صرافی آنلاین ارزدیجیتال با هزاران تراکنش در ثانیه رو با معماری مایکروسرویس طراحی کردیم، یکی از این سرویس‌ها کیف‌پول خواهد بود که سرویس‌های زیادی باهاش در اتباط خواهند بود و این سرویس باید بتونه با دقت موجودی کاربر رو محاسبه کنه. توی این مقاله می‌خوایم چالش‌ها و راهکارهای پیاده‌سازی این سرویس رو بررسی کنیم.خوشحال میشم نظرات‌تون رو در انتها بشنوم :)چالش‌ها:وقتی چندین میکروسرویس (مثل سرویس معامله، سرویس برداشت، سرویس انتقال دارایی) به طور همزمان به سرویس کیف‌پول درخواست بزنن، چند چالش اصلی می‌تونه بوجود بیاد:چالش Lost Update و یا Race Condition:سناریو:کاربر ۱۰۰ تا موجودی داره.درخواست A برداشت ۵۰ تا: خوندن موجودی به مقدار ۱۰۰ تادرخواست B برداشت ۳۰ تا: خوندن موجودی قبل از ذخیره شدن A به مقدار ۱۰۰ تانوشتن درخواست A: مقدار ۱۰۰ منهای ۵۰ مساوی ۵۰ تانوشتن درخواست B: مقدار ۱۰۰ منهای ۳۰ مساوی ۷۰ تانتیجه: دیتابیس میگه موجودی ۷۰ تاست ولی در عمل کاربر ۸۰ تا استفاده کرده و باید موجودی ۲۰ تا باشه. صرافی پول از دست داده.چالش پرفورمنس Hot Row Contention:در صرافی‌ها برای مدیریت کیف‌پول اصلی صرافی و یا کاربرهای وال که هزاران تراکنش در ثانیه دارن، اگر به ازای هر تراکنش قفل بزنیم، دیتابیس به یک Bottleneck تبدیل میشه و CPU درگیر مدیریت قفل‌ها میشه بجای انجام پردازش‌ها.چالش Deadlock ها:سناریو:کاربر A به کاربر B پول میفرسته و کاربر B به کاربر A پول می‌فرسته.ترنزکشن ۱ میاد و A رو لاک می‌کنه و برای B صبر می‌کنه.ترنزکشن ۲ میاد و B رو لاک می‌کنه و برای A صبر کی‌کنه.نتیجه: هردو freeze میشن تا زمانی که دیتابیس time out بشه.چالش Idempotency:اطمینان از اینکه هر درخواست، فقط یکبار اجرا میشه، ممکنه کاربر یا gateway به خاطر تایم‌اوت شبکه چندین بار retry کنه. راهکار اینه که یک مکانیزم برای ایجاد Idempotency-Key یکتا برای هر عملیات مالی ایجاد کنیم و اگر جدید بود برچسب درحال‌اجرا بزنیم و بریم پردازشش کنیم، اگر درحال‌اجرا بود ردش کنیم و یا تو صف بذاریم. اگرم کامل شده بود، نتیجه رو بدون انجام پردازش مجدد براش بفرستیم.چالش Dual-Write: (Outbox Pattern)سناریو: کاربر موجودیش رو ۱۰۰تا اضافه کرده. ما اومدیم و بالانسش رو ۱۰۰ تا بالا بردیم و همزمان روی کافکا هم می‌نویسیم که موجودیش افزایش پیدا کرده که بقیه سرویس‌ها (مثل حسابداری و...) عملیات‌شون انجام بدن. حالا فرض کنین این وسط سیستم مشکل بخوره و موجودی توی ردیس افزایش پیدا کنه اما روی کافکا نوشته نشه. اینجوری atomically write غیر ممکنه.راهکارش اینه که به طور اتومیک ترنزکشن همزمان هم موجودی رو آپدیت کنیم و هم توی یک جدول به صول WAL (Write-Ahead Log) این تغییر موجودی رو به صورت pending بنویسیم و یک سرویس دیگه این جدول رو مانیتور کنه و روی کافکا بنویسه و status شو آپدیت کنه.چالش crash قبل پردازش پیام کافکا:سناریو: فرض کنین که پیام برداشت ۱۰۰ تا از حساب رو از روی کافکا خوندیم، و وسط کار پردازش کرش کرده، دو حالت ممکنه پیش بیاد:کامیت خوندن از کافکا رو قبل از ثبت دیتابیس انجام دادیم: بعد که سرویس بیاد بالا، با اینکه برداشت در دیتابیس ثبت نشده، فک می‌کنه موفق بوده.کامیت خوندن از کافکا رو بعد از ثبت دیتابیس انجام دادیم: توی دیتابیس ثبت کردیم و سیستم بدون کامیت کافکا مشکل خورده و بعد که دوباره بالا میاد، مجدد برداشت رو ثبت می‌کنه.راهکار: استفاده از Checkpointing Strategy با Idempotency یعنی در واقع کامیت رو بعد ثبت در دیتابیس انجام میدیم و به کمک Idempotency مطمئن میشیم که فقط یکبار انجام خواهد شد. چالش دیگه‌ای که وجود داره اینه که کامیت بعد هر پیام کنده که راهکارهاش قابل بررسیه.راهکارها:راهکار Database Pessimistic Locking (Select for Update):نقاط قوت: تضمین می‌کنه که race condition اتفاق نمی‌افته.نقاط ضعف: قاتل پرفرمنسه. همه درخواست‌های دیگه کاربر باید توی صف صبر کنن. اگر لاجیک ما ۱۰۰ میلی‌ثانیه زمان ببره، حداکثر throughput (توان عملیاتی) کاربر ۱۰ درخواست در ثانیه خواهد بود (10 TPS).نتیجه: برای کیف‌پولای با فرکانس پایین خوبه ولی مناسب Hot Wallet ها نیست.راهکار Optimistic Locking (Versioning):به جدول‌ها یک فیلد ورژن اضافه می‌کنیم. موقع درخواست نوشتن چک می‌کنیم که ورژن تغییر نکرده باشه.تریدآف: اگر دیتابیس گزارش بده که ۰ ردیف آپدیت شده، یعنی ورژن تغییر کرده و باید اپلیکیشن retry کنه.نتیجه: در صرافی‌های با فرکانس بالا که هزاران درخواست در ثانیه رو می‌خوان هندل کنن، ۹۹ درصد درخواست‌ها ناموفق میشن و Retry Storm بوجود میاد.راهکار In-Database Atomic Updates (The &quot;Blind Write&quot;):حساب کتاب ریاضی رو توی دیتابیس انجام میدیم: SET balance = balance - 50نقاط قوت: فوق‌العاده سریعه، دیتابیس خودش برای کمترین مقدار ممکن قفل رو مدیریت می‌کنه.نقاط ضعف: مقدار بالانس رو بدون اینکه یک درخواست دوم بزنی و بخونیش، نمی‌دونی. و سخته که لاجیک‌های پیچیده رو به این روش پیاده کرد.راهکار معماری مناسب صرافی:این معماری‌های اولیه رو اول در نظر بگیریم:معماری The Serialized Queue (Async Processing):بجای سروکله زدن با قفل‌ها، با قراردادن همه درخواست‌ها در یک صف، کلا concurency رو از بین می‌بریم.همه درخواست‌ها (خرید/فروش/برداشت/انتقال) رو در یک صف (Kafka/RabbitMQ) به ازای هر user_id قرار می‌دیم. در واقع این همون WAL (Write-Ahead Log) هست.یک Consumer (Worker) واحد به ازای هر user_id قرار میدیم که بخونه و وارد دیتابیس بکنه، چون یک پروسس واحد به ازای هر کاربر این کار رو می‌کنه، دیگه نیازی به database lock وجود نداره.معماری The In-Memory Ledger (Redis + Write-Behind):بالانس کاربر در ردیس نگه‌داری میشه (یا به هر روش دیگه‌ای داخل مموری). و با کمک دستورای (INCRBY/DECRBY) به صورت اتومیک آپدیت میشه. و چون ذاتا ردیس به ازای هر فرمان single-threaded هست، به طور پیش‌فرش atomically safe هست. و اگر ناموفق بود باید کل پروسه رو revert کرد.اما ترفند کار اینجاست که به طور همزمان ما نمیایم توی دیتابیس هم بنویسیم، میایم و لاگ ترنزکشن رو توی queue/DB به صورت Asynchronous می‌نویسیم (Write-Behind).معماری‌های HFT (High-Frequency Trading):این معماری‌ها ساده‌سازی شده که پیچیدگی فهم‌شون کمتر باشه. به عنوان مثال، راهکارهای بعضی از چالش‌هایی که در اول مقاله آوردم رو در نهایت باید بهشون اضافه کرد.معماری LMAX Architecture or CQRS with Event Sourcing:به این روش Event Sourcing pattern with In-Memory state هم می‌گن.کانسپت: ورکر (پروسسر) کارش فقط خوندن و توی دیتابیس نوشتن نیست، بلکه یک stateful microservice هست که بالانس کاربر رو توی RAM نگه می داره.درخواست وارد صف میشه &gt; ورکر ایونت رو می‌خونه &gt; رم رو بلافاصله آپدیت می‌کنه &gt; توی دیتابیس به صورت غیرهمزمان ثبت می‌کنه (background thread).وقتی درخواست بالانس می‌کنی، درخواست رو از یک مسیر خیلی سریع (high-priority channel or RPC) به ورکر می‌فرستی و می‌پرسی که موجودی کاربر در RAM چقدر است؟اگر ردیس به مشکل خورد، دوباره بالانس رو با اجرای دوباره لاگ ترنزکشن‌های ذخیره شده در دیتابیس می‌سازیم. در واقع ما میایم و هر ۱۰ دقیقه یا هر ۱۰ هزار درخواست، کل ردیس رو روی هارد Snapshots می‌گیریم و بعد Crash/Restart آخرین اسنپ‌شات رو لود می‌کنیم و WAL رو از بعد اون اجرا می‌کنیم.معماری The &quot;Pending Balance&quot; Pattern (The Optimistic approach):این روش مرسومی برای کیف‌پول‌هاس استاندارد و یا سیستم‌های بانکی کلاسیکه، ولی مناسب HFT های جدید با توجه به تاخیری که در حد میلی‌ثانیه می‌تونه ایجاد کنه نیست.داده توی ردیس نگه‌داری میشه و توسط ingest service که در واقع API Gateway Layer هست، قبل از صف مدیریت میشه.کاربر درخواست برداشت ۵۰ تا رو میزنه &gt; لایه ورودی (Ingest Layer): بالانس ردیس رو چک می‌کنه که ۱۰۰ تاست، بلافاصله مقدار موجودی ۵۰ تا و موجودی قفل شده ۵۰ تا رو توی ردیس ثبت می‌کنه و درخواست برداشت ۵۰ تا رو به کافکا می‌فرسته &gt; لایه پردازش (Processor): مقدار رو از کافکا می‌خونه، عملیات برداشت رو انجام میده و اگر موفق بود، ایونت تایید رو ارسال می‌کنه &gt; موقعی که رویداد تایید میاد، لایه ورودی مقداد locked_balance رو حذف می‌کنه. اگر برداشت مشکل خورد باید موجودی قفل شده به موجودی اصلی برگردونده بشه.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Tue, 09 Dec 2025 13:37:37 +0330</pubDate>
            </item>
                    <item>
                <title>همه چیز درباره برقراری ارتباط با دیگران</title>
                <link>https://virgool.io/@hamze/%D9%87%D9%85%D9%87-%DA%86%DB%8C%D8%B2-%D8%AF%D8%B1%D8%A8%D8%A7%D8%B1%D9%87-%D8%A8%D8%B1%D9%82%D8%B1%D8%A7%D8%B1%DB%8C-%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D8%A8%D8%A7-%D8%AF%DB%8C%DA%AF%D8%B1%D8%A7%D9%86-ycnfqsuhvrm9</link>
                <description>اینجا می‌خوام درباره یادگیری‌هام و تجربه‌های شخصی و کاری‌ام در زمینه ارتباط با دیگران صحبت کنم؛ تجربه‌ای که حاصل زندگی شخصی و حدود ۱۵ سال کار حرفه‌ایه.اول بذار صورت‌مسئله رو روشن کنم: من در کنار یک آدم دیگه قرار گرفتم که زبان مشترکی داریم و می‌خوایم با کمک ابزارهایی که در اختیار هر دو طرفه، اطلاعات رو منتقل کنیم؛ طوری که نزدیک‌ترین برداشت ممکن از واقعیت ذهنی‌مون برای هم ساخته بشه.اما خب، هنوز مثل کامپیوترها نمی‌تونیم اطلاعات رو «کپی و پیست» کنیم 😅ارتباط موثر در زندگی و کارارتباط موثر در گام اول درون سرِ ما شکل می‌گیردمثل تمامی اهداف زندگی، گام اول، توجه به نگاهی که درباره ارتباط با دیگران داریم هست. این نگاه بخش زیادی از اونچه که اتفاق خواهد افتاد رو شکل میده، پس مهمه که اول انرژی افکارمون رو توی کانال مناسب قرار بدیم:واقعیت‌ها در دسترس من نیستن: مهمه که یادم باشه یک انسانم، و تمام دریافت‌های من، بازتابی از دنیای بیرون در درون منه، یعنی چی؟ یعنی اینکه من هر برداشتی که از مشاهدات و شنیده‌هام می‌کنم، بنا به درک و تجربیات قبلی خودمه، من بدون سوگیری (درباره خطاهای شناختی می‌تونین بخونین - cognitive biases) نمی‌تونم به مسائل نگاه کنم و خب این باعث میشه که همه‌ی واقعیت، اون چیزی که من فک می‌کنم نباشه.برای فهمیدن مساله گفتگو می‌کنم: نمیرم که ثابت کنم یا از موضعی دفاع کنم. در گام اول میرم که بشنوم و بفهمم که مساله درون سر طرف مقابل چیه. هروقت که راهکاری برای حل مساله میاد تو ذهنم، کنار میذارمش و میگم الان فقط قراره مساله رو بفهمم.شاید چیزی ورای فهم من وجود داشته باشه: میرم که کشف کنم، شاید پشت این گفتگو دری وجود داره که هیچوقت ندیدم و این آدم کمک کنه که ببینمش و بازش کنم و بتونم یک رشد در نگاهم و تفکراتم ایجاد کنم. الان مساله کشفه و نه راه‌حل‌های گذشته‌ام.هر گفتگویی قرار نیست منجر به نتیجه بشه، اما اگر نتیجه‌ای قرار باشه دربیاد، باهم میسازیمش: توی گفتگوهای روزمره (و نه کاری) هیچ نیازی نیست که منجر به نتیجه‌گیری مشترک بشه، حتی می‌تونم بگم که نیاز دارم چند روز بهش فکر کنم. یا می‌تونم بگم که توی نگاه‌مون تفاوت وجود داره و خب با توجه به شرایط هر کدوم‌مون شاید هر دو نگاه درست باشه.اگر در نهایت متفاوت فکر می‌کردیم، لازم به اثبات چیزی نیست: من نیازی ندارم برای نگاهی که توی زندگی شخصیم کار می‌کنه، به دیگران اثبات کنم درسته یا نگاه اونا غلطه، ما توی گفتگو، زوایایی که می‌بینیم رو بیان می‌کنیم، اما برای هم تصمیم نمی‌گیریم. در نهایت تصمیم‌گیری یک مساله درونی و شخصیه.حدس زدن گفتگو نیست: هرجایی که وسط صحبت‌ها برداشتی کردم و حدسی زدم، تنها کاری که می‌کنم اینه که بگم من از صحبتت این برداشت رو کردم و بیانش کنم، هر اقدامی غیر این، مسیر ارتباط رو قطع می‌کنه. در نتیجه نه من درباره منظور طرف مقابل حدس میزنم و نه انتظار دارم که طرف مقابل بتونه حدس بزنه که من چی میگم یا می‌خوام.درون سر دو اصل کلیدیه که وجود داشته باشه: من برای کشف، گفتگو می‌کنم - حدس زدن بخشی از گفتگو نیست، گفتگو فقط با صحبت کردن شکل می‌گیره.و بعد از مرتب کردن درون سر، زبان‌مان هم نیاز به تمرین داردمهمه که چطور بیان می‌کنیم. همه آدم‌ها تعاریف مختلف خودشون رو دارن، کلمات کیفی مثل خوب، بد، زیبا، لذت‌بخش، آزار دهنده و... هزاران کلمه دیگه، توی سر هر کس معنی متفاوتی می‌تونن داشته باشن. پس چطور حرفم رو درست منتقل کنم؟ ساختار جمله زیر تا حد خوبی کمک می‌کنه:من + &quot;مشاهداتم&quot; + &quot;حسم&quot; + &quot;چیزی که نیازمه&quot;من وقتی جلوی غریبه‌ها بهم میگی جوجه، حسم اینه که جدیم نمی‌گیری و به بقیه این فضا رو میدی جدی نگیرنم. دوس دارم که جلوی غریبه‌ها باهام با احترام صحبت کنی (و با مثال بگی با احترام یعنی چی)من وقتی می‌بینم گزارش‌ها دیر ارسال می‌شن، حس می‌کنم تیم هماهنگ نیست. دوست دارم قبل ددلاین یه اطلاع‌رسانی کوتاه انجام بدیم تا بتونم منابع رو تنظیم کنم.چندتا بخش مهم اینطور صحبت کردن رو باهم بررسی کنیم:شروع با من: این یعنی من از سمت خودم و چیزی که تجربه کردم صحبت می‌کنم. توی ارتباط این کلیدیه - وقتی با کلمه‌ی تو شروع کنم و مثلا بگم تو بهم احترام نمی‌ذاری، اصلا ملوم نیست از چی صحبت می‌کنم و چیزی که من تجربه کردم رو بیان نمی‌کنه. از طرف دیگه، این جمله بجای اینکه تمرکزش روی مساله من باشه، بار معنایی رو میبره روی طرف مقابل، و این باعث میشه که طرف مقابل حس کنه بهش حمله شده، چون دارم طرف رو زیرسوال میبرم، و معمولا اولین واکنش طرف مقابل گارد گرفتن خواهد بود.از مشاهدات بگو: اولین چیزی که میگم، دقیقا اتفاقی هست که با حواس پنج‌گانه‌ام تجربه کردم و نه هیچ‌چیز دیگه - نه اون فکری که تو سرمه یا حسی که تجربه کردم - کلیدیه که دقیق بتونم اتفاقی که تجربه کردم رو بیان کنم تا دقیقن طرف مقابلم بدونه از چی صحبت می‌کنم.از حست بگو: خب حالا که مشاهدات رو گفتم، وقتشه بگم که درونم درباره اون اتفاق چی رو تجربه کردم، چون دریافت آدم‌ها نسبت به اتفاقات متفاوته، وقتی حسم رو می‌گم، کمک می‌کنم که طرف مقابل بتونه درک کنه که چی رو تجربه کردم و بهش این فرصت رو بدم که باهام همدلی کنه.از انتظارت بگو: آدم‌ها نیازهای متفاوتی دارن، پس اینکه حسم رو بگم کافی نیست و طرف مقابل نمی‌تونه نیازم رو حدس بزنه، پس لازمه نیازم رو واضح بگم و دربارش صحبت کنم.توی این ساختار حرفت رو بزن: من + چی مشاهده کردم + چه حسی رو تجربه کردم + چه انتظاری دارمو آن زمان که بدن نیز حرف می‌زندراستش زبان بدن به‌قدری گسترده‌ست که پرداختن کامل بهش در این مقاله ممکن نیست، اما وقتی صحبت از ارتباط میشه، نمی‌شه ازش حرفی نزد.متخصصان زبان بدن معتقدند حدود ۷۰٪ ارتباط ما با دیگران از طریق زبان بدن و تن صدامونه و تنها حدود ۳۰٪ به ساختار جملات و کلمات اختصاص داره. در ادامه چند نکته‌ی ابتدایی اما مهم رو مرور می‌کنم:تماس چشمی برقرار کن: حدود ۷۰٪ زمان مکالمه به محدوده‌ی بین دو ابرو و بینی طرف مقابل نگاه کن. نگاه مستقیم و طولانی توی چشم ممکنه طرف رو معذب کنه، و نگاه نکردن نشونه‌ی بی‌توجهی برداشت میشه.به تن صدات توجه کن: تن صدا می‌تونه هیجان، تمرکز و تأکیدت رو منتقل کنه. صحبت کردن با تن صدای یکنواخت، آروم و بی‌انرژی، حس بی‌علاقگی یا خستگی رو منتقل می‌کنه.حالت نشستن نشونه‌ی علاقه‌ست: به‌طور ساده، جهت بدن، جهت فکره. پس به سمت طرف مقابل بشین و بدنت رو کمی متمایل کن. اگه پاهات به سمت در باشه، ناخودآگاه این پیام رو می‌فرستی که منتظری زودتر بری.به حالت دست‌هات دقت کن: زبان بدن باز، نشونه‌ی پذیرا بودنه. سعی کن دست‌به‌سینه نشینی، دست‌هات رو توی هم گره نزنی و جلوی بدنت رو با کیف یا لیوان نپوشونی. دیده شدن کف دست‌ها حس اعتماد ایجاد می‌کنه.موقع گوش دادن بازخورد بده: با حرکات آروم سر می‌تونی نشون بدی که گوش می‌دی. حواست باشه تکون سریع و مکرر سر، ممکنه به‌عنوان نشونه‌ی عجله برای تموم شدن بحث برداشت بشه.گوشی و ساعت رو کنار بذار: نگاه کردن به گوشی یا ساعت نه‌تنها نشونه‌ی بی‌توجهیه، بلکه به طرف مقابل این پیام رو می‌ده که منتظری گفت‌وگو زودتر تموم بشه.بدن طرف مقابل رو بخون: زبان بدن ناخودآگاه‌تر از زبان گفتاره و برای همین اغلب، اطلاعات صادقانه‌تری منتقل می‌کنه. با تمرین می‌تونی از زبان بدن طرف مقابل به میزان صداقت، راحتی و احساسات واقعی‌ش پی ببری. این مهارت به زمان و تمرین نیاز داره و پرداختن کامل بهش جاش توی این مقاله نیست.در محیط کار، قواعد کمی متفاوت استتوی محیط کار یک تفاوت اصلی وجود داره، اینکه باید بتونیم تهش به جمع‌بندی و خروجی برسیم. برای همین علاوه بر قواعدی که دربارش صحبت کردم، چندتا قاعده دیگه می‌تونه کمک‌مون بکنه:موضوعات مهم، داکیومنت می‌خوان: معمولا برای جلسات مهم کاری جلسات ترتیب داده میشه، یادمون باشه که &quot;تصمیم‌گیری&quot; یک پروسه زمان‌بر می‌تونه باشه، برای همین، آماده کردن داکیومنت و ارسالش به افراد حاضر در جلسه، قبل از جلسه، می‌تونه کمک کنه که جلسه موثر تر پیش بره، پیشنهادم بیان این موارده: شرح مساله، شرح راه‌حل‌های پیشنهادی، مواردی که توی جلسه قراره براشون تصمیم‌گیری بشه، خروجی مورد انتظار جلسه.عددها صحبت می‌کنن: توی فضای کاری، استفاده‌نکردن از صفات کیفی مهم‌تر میشه. بجای اینکه بگیم وضعیت فروش خوب نیست، از اعداد، جدول‌ها، مقایسه‌ها، نمودارها و چارت‌ها استفاده کنیم.از همه حواس ۵ گانه استفاده کن: هرچی مساله پیچیده‌تر باشه، سعی کن حواس بیشتری رو درگیر کنی، وقتی به جلسه نمودار و چارت اضافه کنی، بینایی طرف هم درگیر کردی، اگر نمونه محصول رو بیاری تو جلسه، لامسه و حتی بویایی رو هم درگیر کردی. نقطه اتصال‌های اولیه ما برای ارتباط ایناس، هرچی بیشتر استفاده کنی، بیشتر آدما می‌تونن ارتباط بگیرن.داستان واقعیت رو بگو: وقتی از ورودی‌ها که حواس ۵گانه هستن گذر کردی، دو نقطه دیگه برای فتح باقی می‌مونه. منطق و حس (مغز و قلب) با اعداد و نمودارها و جداول مقایسه‌ای به منطق نفوذ کن و با بیان صادقانه تجربیات گذشته خودت و تجربیات مشابه دیگران به قلب‌ نفوذ کن. آدم‌ها با داستان‌های مشابه خیلی سریع درگیر میشن و می‌تونن ارتباط حسی برقرار کنن.برای ساختن برو و نه اثبات کردن: به نظرم شاید این مهم‌ترین باشه که قبل جلسه با خودت تکرار کنی که دارم میرم توی جلسه تا باهم بهترین مسیر رو بسازیم، پس میرم که خوب گوش بدم، در مورد جنبه‌های مختلف صحبت کنیم و باهم دیگه بهترین راه‌حل رو بسازیم. پس راه‌حل‌های توی سرت رو قطعی ندون.چند تکنیک برای ارتباط موثرترگوش دادن فعالانه: برای اینکه مطمئن‌شم خوب به طرف مقابل گوش دادم و منظورش رو درست متوجه شدم، بعد تموم شدنش حرفش، خلاصه حرفش رو تکرار کنم: من از حرفات این رو متوجه شدم که ...رهایی از راه‌حل‌های ذهنی: خیلی وقتا وسط صحبت کردن طرف مقابل، ذهنم درگیر پاسخ به یک جمله‌اش میشه و این باعث میشه که بقیه صحبت‌هاش نشنوم و تو فکرم فرو برم. یک دفتر همرام میبرم و یادداشت می‌کنم و برمی‌گردم به گوش کردن فعالانه، چون مطمئنم چیزی دیگه فراموش نمیشه.سوال باز بپرس: این رو قبلا گفتم و باز تکرار می‌کنم، حدس زدن جزئی از ارتباط نیست، اگر چیزی برام واضح نیست، یک سوال میپرسم که دقیق‌تر برام شرح بده. یا میگم من برداشتم اینه ... که بتونه تصحیحش کنه.گفتگو چالشی: گاهی گفتگو از فضای سازنده خارج میشه، چه زمانی؟ زمانی که حس‌هایی مثل خشم، هیجان یا هر حس شدید دیگه‌ای بر گفتگو حاکم بشه، این زمان، زمان هیچ نوع تصمیم‌گیری‌ای نیست، فقط می‌گم که: الان خیلی خشمگینم، نیاز دارم که آروم‌تر بشم (بشی) تا در این مورد تصمیم بگیریم، فردا (یک ساعت دیگه) دربارش صحبت کنیم.گاهی روی تصمیمات باید خوابید: این مورد شاید خیلی مرتبط با ارتباط نباشه، اما خواستم بهش اشاره کنم که تصمیمات بزرگ نیاز به اطمینان داره و بخشی از این اطمینان از جایی میاد که مطمئن بشیم که هیجانی نبودن، برای همین خوبه که برای تصمیمات بزرگ صبر کنم که یک روز بگذره و فردا مطمئن شم هنوز تصمیم‌ام همونه و همه جنبه‌ها رو دیدم یا نه و بعد با طرف مقابل درمیون بذارم.من حمزه قائم‌پناه هستم و این پست رو برای کامیونیتی فنی بیلدآپ نوشتم (تلگرام: build_up_team)</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Tue, 14 Oct 2025 12:54:07 +0330</pubDate>
            </item>
                    <item>
                <title>یک دوری با Ansible بزنیم</title>
                <link>https://virgool.io/@hamze/%DB%8C%DA%A9-%D8%AF%D9%88%D8%B1%DB%8C-%D8%A8%D8%A7-ansible-%D8%A8%D8%B2%D9%86%DB%8C%D9%85-spiq0c7lbrbe</link>
                <description>انسیبل یک سری از ابزارهای رو برای Infrastructure as Code (IaC) در اختیارمون میذاره که به کمکش می‌تونیم مدیریت کانفیگ‌ها، دپلوی برنامه، orchestration و کلی کارای دیگه رو انجام بدیم.آموزش Ansibleمفهوم Playbook:به اسکریپت‌های انسیبل که به فرمت YAML هستن که برای اتومات کردن تسک‌ها می‌نویسیم‌شون، playbook می‌گیم.مفهوم Control node:ماشینی که روش Ansible CLI tools رو اجرا می‌کنیم که از طریق اون، نودها رو مدیریت می‌کنیم.ویژگی‌های Ansible:به صورت Agent-less: یعنی لازم نیست روی سرورهایی که می‌خوایم کانفیگ‌شون کنیم، چیزی نصب کنیم. بلکه فقط روی سرور اصلی یا همون لوکال‌مون نصب میشه و از طریق SSH به سرورها متصل میشه و کانفیگ‌شون می‌کنه.قابلیت رشد: خیلی راحت میشه اتومات روی کلی سرور و سرویس کلاد رشدش داد و به صورت ماژولار توسعه پیدا می‌کنه.پیش‌بینی‌پذیری: وقتی سیستم در وضعیتی هست که توی playbook تعریف کردیم، Ansible چیزی رو تغییر نمیده، حتی اگر بارها playbook اجرا بشه.شروع اتومات کردن با Ansible:اول نصب کنیم و یک پروژه ایجاد کنیم:pip install ansible
mkdir ansible_quickstart &amp;&amp; cd ansible_quickstartایجاد یک inventoryدر واقع inventory یک کانفیگ فایله که گروه‌ها و مشخصات سرورهای هر گروه رو مشخص می‌کنیم. در داخل پروژه با نام: inventory.ini (میتونه فرمت YAML هم باشه)[myhosts]
192.0.2.50
192.0.2.51
192.0.2.52برای verify و ping کردن فایل inventory: (از -u برای مشخص کردن user می‌تونیم استفاده کنیم)ansible-inventory -i inventory.ini --list
ansible myhosts -m ping -i inventory.iniتولید متا گروه: می‌تونیم چند گروه رو هم در یک گروه بزرگتر قرار بدیم.افزودن متغیر: متغیرها برای مدیریت نودهاس مثل مشخص کردن port, ssh user و غیره. که می‌تونه برای یک هاست مشخص و یا گروه تعریف بشه.نکات نام‌گذاری Inventory:اسامی یکتا و با‌معنی باشن و case sensitive هستن.بجای space از آندرلاین استفاده کنین.برمبنای what (گروه بندی هاست‌ها براساس توپولوژی: db, web, leaf)، where (گروه بندی هاست‌ها برمبنای موقعیت: datacenter, region, floor, building)، when (گروه‌بندی برمبنای محیط: test, staging, production) نام گذاری کنین.ساخت یک playbook:پلی‌بوک یک برنامه اتومیشن به فرمت YAML هست که انسیبل استفاده می‌کنه تا نودهایی که مدیریت می‌کنه رو آماده و کانفیگور کنه. پلی‌بوک لیستی از play ها است که Ansible از بالا به پایین انجام میده تا به هدف کلی برسه.مفهوم Play:یک لیست از تسک‌ها که مرتبط با نودهای مدیریت شده در inventory هست. (تعریف what, who)مفهوم Task:یک رفرنس به یک ماژول که عملیاتی که Ansible انجام میده رو تعریف می‌کنه. مفهوم Module: یک واحد کد یا باینتری که Ansible روی نود مدیریت‌شده اجرا می‌کنه. ماژول‌های Ansible در کالکشن‌هایی برای هر ماژول گروه‌بندی شدن. (فانکشن‌های از پیش نوشته شده‌ای مثل apt, yum, copy)نوشتن یک playbook که سرورها رو پینگ کنه و پیام hello world رو چاپ کنه: (فایل playbook.yaml)- name: My first play
  hosts: myhosts
  tasks:
   - name: Ping my hosts
     ansible.builtin.ping:

   - name: Print message
     ansible.builtin.debug:
       msg: Hello worldاجرای فایل playbook:ansible-playbook -i inventory.ini playbook.yamlمفهوم Handlers:یک نوع خاص Task که فقط زمانی اجرای میشه که توسط تسک‌های قبلی فراخونی بشه که یک تغییری ایجاد کردن.مفهوم Roles:به محتواهای reusable Ansible که می‌تونه task, handler, variable, plugin و... باشه، که می‌تونیم ازشون داخل Play ها استفاده کنیم، می‌گیم Role.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sat, 11 Jan 2025 14:52:43 +0330</pubDate>
            </item>
                    <item>
                <title>PostgreSQL High Availability</title>
                <link>https://virgool.io/@hamze/postgresql-high-availability-lhlmzhvgqtey</link>
                <description>هدف از دسترس‌پذیری بالا (HA)دسترس‌پذیری بالا تضمین می‌کنه که سیستم پایگاه داده حتی در زمان خرابی‌ها، عملیاتی باقی می‌مونه و زمان پایین بودن و از دست دادن داده‌ها رو کاهش میده.PostgreSQL High Availabilityکلمات کلیدی برای PostgreSQL HAمفهوم Replication: یعنی یک نسخه اضافه از داده‌ها رو روی یک نود دیگه نگهداریم. به دو روش اصلی می‌تونیم این کار رو انجام بدیم:تکثیر هم‌زمان Synchronous Replication: اطمینان می‌ده که داده‌ها قبل از تایید تراکنش (commit) توی سرور اصلی و سرورهای ثانویه نوشته شده. این روش اطمینان خوبی ارائه می‌ده اما ممکنه باعث ایجاد تاخیر (lag) شود.تکثیر غیرهم‌زمان Asynchronous Replication: داده‌ها رو ابتدا توی سرور اصلی می‌نویسه و بعدش به صورت غیرهم‌زمان به سرورهای ثانویه منتقل می‌کنه. این روش سریعتره اما در صورت به مشکل‌خوردن، احتمال از دست دادن داده‌ها وجود داره.مفهوم Quorum Commit: حدنصابی که برای تایید نوشته شدن در نودهای ثانویه نیازه تا بگیم موفقیت‌آمیز بوده. این روش بین سرعت و اطمینان تعادل ایجاد می‌کنه. مثلا اگر سه سرور داریم، حدنصاب مناسب می‌تونه ۲ باشه، یعنی اگر ۲ سرور تایید بدن که نوشتن انجام شده، نوشتن رو موفق در نظر می‌گیریم.مفهوم Failover: به فرایندی می‌گیم که، موقع به مشکل خوردن سرور اصلی، یک سرور آماده جایگزین سرور اصلی بشه که سیستم به مشکل نخوره. این فرایند می‌تواند:انتقال دستی Manual Failover: نیاز به مداخله انسانی داره.انتقال خودکار Automatic Failover: به طور اتومات توسط ابزارهایی مانند repmgr، Patroni یا pg_auto_failover مدیریت می‌شه.مفهوم (Load Balancing): درخواست‌های خوندن را بین سرورهای آماده توزیع می‌کند تا عملکرد بهبود پیدا کنه و بار سرور اصلی کاهش بیابه.مفهوم Connection Pooling: ابزارهایی مانند PgBouncer یا Pgpool-II که کانکشن‌های پایگاه داده رو مدیریت می‌کنن که، به طوری که یکسری کانکشن باز و آماده رو مدیریت می‌کنن تا حجم زیاد درخواست‌ها رو بتونن از طریق اونها مدیریت کنن و مساله کمبود کانکشن رو تا حدی مدیریت کنن.مفهوم Single Point of Failure: در واقع وقتی سیستم وابسته به یک سرویس در یک نقطه باشه، در  صورتی که اون نود یا سرویس با مشکل روبرو بشه و جایگزینی براش نباشه، اون رو یک نقطه شکست می‌گیم که کل سیستم رو می‌تونه دچار مشکل کنه.پیاده‌سازی PostgreSQL HA روی سه نودنمای کلی تنظیماتسرور اصلی: سرور اصلی که تمام عملیات نوشتن را مدیریت می‌کند.سرورهای رپلیکا: دو نسخه فقط خواندنی از سرور اصلی.ابزار Docker: برای کانتینری کردن PostgreSQL و اطمینان از قابلیت حمل.ابزار Repmgr: ابزاری محبوب برای مدیریت تکثیر و انتقال وظایف در PostgreSQL.نحوه عملکردنود اصلی: نوشتن‌ها رو قبول می‌کنه و داده‌ها را به نودهای آماده (replica - secondary) منتقل می‌کنه.نودهای ثانویه: عملیات خوندن می‌تونه از روی اینا انجام بشه.اگر نود اصلی خراب بشه،repmgr به طور خودکار یکی از نودهای آماده رو به عنوان نود اصلی ارتقا می‌ده.پیکربندی Docker Composeاین داکر کامپوز رو روی سه سرور بالا میاریم، توجه داشته باشیم که متغیرهای env هر سرور متفاوت هستن و باید فایل .env در کنار فایل داکر کامپوز هر یک از این سه سرور موجود باشه:version: &#039;2&#039;

services:
  db:
    container_name: postgres_db
    image: 192.168.0.33:5000/postgresql-repmgr:17
    ports:
      - 5432:5432
    volumes:
      - db-data:/bitnami/postgresql
    environment:
      - POSTGRESQL_POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRESQL_USERNAME=${DB_USER}
      - POSTGRESQL_PASSWORD=${DB_PASS}
      - POSTGRESQL_DATABASE=${DB_NAME}
      - REPMGR_PASSWORD=${REPMGR_PASSWORD}
      - REPMGR_PRIMARY_HOST=${DB_MASTER_IP}
      - REPMGR_PARTNER_NODES=${DB_MASTER_IP},${DB_SLAVE1_IP},${DB_SLAVE2_IP}
      - REPMGR_NODE_NAME=${REPMGR_NODE_NAME}
      - REPMGR_NODE_NETWORK_NAME=${DB_CURRENT_SERVER_IP}
      - REPMGR_NODE_ID=${REPMGR_NODE_ID}
      - REPMGR_FAILOVER=automatic
      - REPMGR_PROMOTE_COMMAND=&#039;repmgr standby promote&#039;
      - REPMGR_FOLLOW_COMMAND=&#039;repmgr standby follow&#039;
      - POSTGRESQL_EXTRA_FLAGS=--synchronous_standby_names=&amp;quot2 (${DB_SLAVE1_IP}, ${DB_SLAVE2_IP})&amp;quot
    networks:
      - net-backend

volumes:
  db-data:

networks:
  net-backend:
    name: net-backend
    driver: bridgeنمونه فایل env:REDIS_MASTER_IP=192.168.0.44
REDIS_CURRENT_SLAVE_IP=192.168.0.45

DB_CURRENT_SERVER_IP=192.168.0.1
DB_MASTER_IP=192.168.0.1
DB_SLAVE1_IP=192.168.0.2
DB_SLAVE2_IP=192.168.0.3
DB_USER=postgres
DB_PASS=pass
DB_NAME=my_db

REPMGR_PASSWORD=repmgrpass
POSTGRES_PASSWORD=postgrespass
REPMGR_NODE_NAME=node-0        # Change for each node: node-1, node-2
REPMGR_NODE_ID=1               # Change for each node: 2, 3توضیح پیکربندیبخش Image: تصویر PostgreSQL با repmgr برای مدیریت HA مشخص شده.متغیرهای محیطی: تنظیمات PostgreSQL و repmgr مانند اطلاعات کاربری، نودهای ثانویه و رفتار انتقال وظایف را پیکربندی می‌کنه.بخش Volumes: داده‌های پایگاه داده را در برابر راه‌اندازی مجدد کانتینر پایدار نگه می‌داره.بخش Network: اطمینان از ارتباط تمام نودها در یک شبکه.بخش Synchronous Standby: اطمینان از هم‌زمان بودن دو نود آماده برای حداقل کردن از دست دادن داده.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sun, 29 Dec 2024 13:37:54 +0330</pubDate>
            </item>
                    <item>
                <title>نماد O بزرگ؛ زمانی که پای عملکرد الگوریتم به وسط می‌آید</title>
                <link>https://virgool.io/@hamze/%D9%86%D9%85%D8%A7%D8%AF-o-%D8%A8%D8%B2%D8%B1%DA%AF-%D8%B2%D9%85%D8%A7%D9%86%DB%8C-%DA%A9%D9%87-%D9%BE%D8%A7%DB%8C-%D8%B9%D9%85%D9%84%DA%A9%D8%B1%D8%AF-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85-%D8%A8%D9%87-%D9%88%D8%B3%D8%B7-%D9%85%DB%8C-%D8%A2%DB%8C%D8%AF-otlwpds1dtz5</link>
                <description>توی طراحی یک نرم‌افزار با عملکرد بالا، چیزی که مهمه اینه که متوجه باشیم الگوریتم‌مون از چه پیچیدگی زمانی‌ای استفاده می‌کنه.پیچیدگی O(1)مفهوم: پیچیدگی زمانی ثابت (Constant)، یعنی هر ورودی که بهش بدی، یک میزان ثابت زمان می‌بره که اجرا بشه، یعنی عملکردش وابسته به سایز ورودی نیست.مثال: دسترسی به یک المان آرایه به کمک index اون و یا اضافه یا حذف کردن یک المان از یک hash table. (جدول هش ساختار داده‌ای هست که از جنس key, value هست و به کلیدهاش به مقادیرش دسترسی پیدا می‌کنیم.)پیچیدگی O(log n)مفهوم: پیچیدگی زمانی لگاریتمی (Logarithmic)، یعنی اینکه زمان اجرا با سرعت کمتری نسبت به رشد ورودی افزایش پیدا می‌کنه. میشه اینطور در نظر گرفت که با ضریب حدودا نیم به ۱ زمان نسبت به ورودی اضافه میشه.مثال: جستجوی دودویی (binary search) روی یک آرایه مرتب و یا عملیات روی یک درخت جستجوی دودویی بالانس شده.پیچیدگی O(n)مفهوم: پیچیدگی زمانی خطی (Linear)، یعنی اینکه با نسبت ۱ به ۱ (مستقیم) براساس ورودی الگوریتم، تایم اجراش بیشتر میشه.مثال: پیدا کردن مینیموم و ماکسیموم در یک آرایه غیر مرتب.پیچیدگی O(n logn)مفهوم: پیچیدگی خطی لگاریتمی (Linearithmic)، این ترکیبی از پیچیدگی زمانی خطی و لگاریتمی هست. یعنی مثلا چیزی در حدود ۱.۵ به ۱ زمان نسبت به ورودی رشد می‌کنه.مثال: روش‌های مرتب‌کردن عملکرد بالا مثل merge sort,  quick sort, heap sort. در واقع میشه گفت یک لوپ روی ورودی دارن که درونش یک لوپ روی نصف ورودی داره.پیچیدگی O(n^2)مفهوم: پیچیدگی زمانی توان ۲ (Quadratic)، زمان اجرا به صورت تصاعدی با سایز ورودی اضافه میشه.مثال: الگوریتم‌های مرتب کردن ساده مثل bubble sort, insertion sort, selection sort. در واقع الگوریتم‌هایی که دو بار لوپ روی ورودی میزنن.پیچیدگی O(n^3)مفهوم: پیچیدگی زمانی توان ۳ (Cubic)، زمان اجرا خیلی بیشتر با هر افزایش ورودی بسیار بیشتر اضافه میشه.مثال: الگوریتم ضرب دو ماتریکس با یک الگوریتم ابتدایی، در واقع میشه گفت کدی که ۳ لوپ تو در تو روی وردی‌ها داره.پیچیدگی O(2^n)مفهوم: پیچیدگی زمانی نمایی (Exponential)، با اضافه شدن هر ورودی جدید، زمان اجرا ۲ برابر میشه، این وحشتناکه، برای درکش مثال بزنم، مثلا با ۵ ورودی ۱ ثانیه طول می‌کشه، با ۶ تا ۲ ثانیه، با ۷ تا ۴ ثانیه، می‌تونین حساب کنین با ۲۰ تا چند ثانیه؟ به نظر یه چیزی حدود ۱۲ روز میشه :)مثال: الگوریتم‌هایی که به صورت بازگشتی (recursive) مسائل رو با تقسیم کردن به چندین زیر مساله حل می‌کنن.پیچیدگی O(n!)مفهوم: پیچیدگی زمانی فاکتوریل (Factorial)، با افزایش ورودی سر به فلک می‌کشه :))مثال: الگوریتم‌هایی که همه حالت‌های ممکن رو چک می‌کنن تا به جواب درست برسن، الگوریتم‌های جای‌گشت (Permutation Algorithms). پیچیدگی O(sqrt(n))مفهوم: پیچیدگی زمانی جزر (Square root)، زمان اجرا متناسب با جزر ریشه ورودی اضافه میشه.مثال: در واقع الگوریتم‌هایی که توش یک لوپ با گام‌های جزر n داریم، مثل الگوریتم پیدا کردن اعداد اول.ترتیب عملکردهمه پیچیدگی زمانی‌هایی که آوردم به ترتیب عملکرد از کارا ترین آورده شده، فقط پیچیدگی جزری رو آخر آوردم چون متداول نیست ولی در عمل بین لگاریتمی و خطی قرار می‌گیره.با سپاس از ByteByteGo برای این اینفوگراف خوشگلش :)</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Tue, 08 Oct 2024 11:13:37 +0330</pubDate>
            </item>
                    <item>
                <title>دروازه API ها چیه و چه کمکی می‌تونن بکنن؟ - API Gateway</title>
                <link>https://virgool.io/@hamze/%D8%AF%D8%B1%D9%88%D8%A7%D8%B2%D9%87-api-%D9%87%D8%A7-%DA%86%DB%8C%D9%87-%D9%88-%DA%86%D9%87-%DA%A9%D9%85%DA%A9%DB%8C-%D9%85%DB%8C-%D8%AA%D9%88%D9%86%D9%86-%D8%A8%DA%A9%D9%86%D9%86-api-gateway-qw4apiym0cm8</link>
                <description>دروازه API ها یا API Gateway یک واسطه که بین کاربرها و سرویس‌ها قرار می‌گیره. به این صورت که همه درخواست‌های کاربرها میان به این واسط و از اونجا هر درخواست به سرویس و endpoint مرتبطش ارسال میشه. در واقع یک نقطه ورود مرکزی برای همه کاربرهاست.چرا بهش احتیاج داریم؟جواب ساده اینکه اگر فکر می‌کنین که بهش احتیاجی ندارین و کار بدون این انجام میشه، خب بهش فعلا حداقل احتیاجی ندارین :)اما این کارا رو به کمکش می‌تونین انجام بدین:اعتبار سنجی پارامترها (Parameter Validations): چک کردن پارامترهایی که همراه درخواست اومده و برگشت زدن درخواست در صورت اشتباه بودن‌شون.چک کردن اجازه دسترسی (Whitelist Verification): اجازه دسترسی به کل سرویس‌ها رو بر اساس IP یا User Agent و یا هرچیز دیگه‌ای مدیریت می‌کنه و کاربرد امنیتی داره.اعتبارسنجی و بررسی دسترسی کاربر (Authentication and Authorization): وضعیت لاگین و اجازه دسترسی به بخشی که درخواست کردن رو چک می‌کنه.محدودیت نرخ درخواست (Rate Limiting): نرخ درخواست‌ها به سرویس‌ها رو چک می‌کنه و می‌تونه محدودیت ایجاد کنه تا سرویس‌ها زیر بار غیر استاندارد نرن و مشکل نخورن.مسیریابی (Routing): درخواست برای رسیدن به سرویس مناسب هدایت می‌کنه. اینجا ممکنه Load Balance هم اتفاق بیوفته که ترافیک بین نمونه‌های یکسان یک سرویس توزیع بشن تا عملکرد سریع‌شون حفظ بشه.پیدا کردن سرور سرویس (Service Discovery): یک مکانیزمه که این امکان رو میده که متوجه اضافه شدن یا حذف شدن یک سرویس بشه. به این صورت به طور داینامیک می‌تونن سرویس‌ها رشد کنن.ایجاد تغییر در درخواست (Request Transformation): ایجاد تغییر در درخواستی که اومده، مثلا header, body و یا method اش رو تغییر بده.و در همه این موارد هم می‌تونیم کش، لاگ و مدیریت خطاها رو داشته باشیم و روی سرویسی مثل Elastic Search و Kibana بفرستیم که بتونیم این دیتاها رو بررسی کنیم.چطور راه بندازیمش؟سرویس‌های ابری مطرح مثل Amazon, Azure, Google Cloud این سرویس رو در اختیار می‌گذارن اما راهکارهای Open-source ای مثل Kong هست. چیزی که من متداول‌تر توی شرکت‌هایی که کار کردم دیدم استفاده از HAProxy و در صورت نیاز ‌Nginx برای این کار بوده.مرسی از ByteByteGo برای این اینفوگراف‌های خوشگلش :)</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sat, 05 Oct 2024 15:02:01 +0330</pubDate>
            </item>
                    <item>
                <title>کتاب انسان در جستجوی معنا</title>
                <link>https://virgool.io/@hamze/%DA%A9%D8%AA%D8%A7%D8%A8-%D8%A7%D9%86%D8%B3%D8%A7%D9%86-%D8%AF%D8%B1-%D8%AC%D8%B3%D8%AA%D8%AC%D9%88%DB%8C-%D9%85%D8%B9%D9%86%D8%A7-b8mg0rfxfsa0</link>
                <description>کتاب انسان در جستجوی معنا، اثر ویکتور فرانکل هست که یک پزشک متخصص مغز یهودی بوده که در زمان جنگ‌جهانی در اردوگاه‌های کار اجباری نازی‌ها به‌سربرده و از خاطرات اونجا و معنایی که در میان اون سختی‌ها برای زندگی پیدا کرده می‌گه. این متن، خلاصه کتاب نیست، بلکه برداشت‌ها و یا نقل‌قول‌های کلیدی از نگاه منه که اینجا نگه‌شون داشتم :)به فردی که اجباری نداشت روزی ۱۲ ساعت روی زمین باتلاقی کار کنه حسادت داشتیم، به اینکه لازم نبود بیل بزنه تا لوله‌ها رو توی زمین بذاره قبطه می‌خوردیم.کسی نمی‌تونه تصور کنه صدای منحوس آژیر خطر هم می‌تونه خوشایند باشه وقتی که اگر به صدا نمیومد از شدت خستگی میمردی.ما هیچ چیزی را مالک نبودیم، تنها خوش شانسی ما این بود که تن ضعیف‌مون رو مالک بودیم.در نهایت آنچه به سقوط حالت روحی و درونی زندانی منجر میشد، آنچنان به شرایط روانی، جسمی و محیط زندان وابسته نبود، بلکه نتیجه تصمیم زندانی بود.تنها کسانی قربانی آثار ویران کننده زندگی اردوگاهی شده‌اند که اجازه کم شدن سیرت معنوی و اخلاقی خود را داده‌اند. - با مذهبی متفاوته :)زندگی موقتِ نامحدود.دور کردن واقعیت از شرایط موجود، همه چیز رو بی‌معنا می‌کنه. این شرایط مجالی میده که از نظر روحی فراسوی خود بری. این شرایط اومدن تا سد راه بشن و بتونی شیوه برداشتنشون رو یاد بگیری، اما بعضی‌ها بجاش سختی‌ها رو کوچک میشمردن، به عنوان چیزی که نتیجه‌ای با خودش نداره، و غرق شدن در زندگی گذشته رو برتری می‌دادند. که این باعث میشد زندگی براشون بی‌معنی بشه.زندگی مثل رفتن به دندون‌پزشکیه، چون انسان همواره در انتظار دردناک‌ترین لحظه‌هاست، با اینکه اون لحظات رو پشت سر گذاشته.با نشون دادن هدف‌های آینده، دریچه امیدی براش باز بشه.کسی که چرایی برای زندگی‌کردن داره، از عهده چگونگی اون برخواهد آمد.زمانی که آدمی آگاه می‌شه که سرنوشتش رنج بردنه، به اجبار رنجش را به عنوان وظیفه‌ای منحصر به فرد می‌پذیرده و می‌پذیره که هیچ‌کس نمی‌تونه بجاش رنج بکشه و از سختی‌ها رهاش کنه. نحوه تحمل و مواجهه با مشکلات تنها فرصتیه که داره.تحمل رنج ایجاد کننده فرصت‌هایی است که به کمک آن به کمال می‌رسیم.بی‌همتایی و یگانگی که هر فرد را از دیگری متمایز می‌کنه و هرکس مسئولیتی داره و قابل جایگزینی نیست یعنی کسی به جای اون نمی‌تونه انجامش بده، در مقابل کاری ناتمام یا انتظار کشیدن دیگران برای او، معنی خودکشی از بین می‌ره.معنا درمانی بر این اصل تکیه داره که پذیرش مسئولیت بسیار مهمه. چنان زندگی کن که انگار بار دومه توی این جهانی و امروز در حال برطرف کردن اشتباهاتی هستی که بار اول انجام دادی. ❤خودت انتخاب کن در برابر چه چیز و چه کس چقدر مسئولی.انتخاب اینکه در برابر وظیفه‌ای که زندگی بر دوشش گذاشته، به افرادی ویژه پاسخگو باشه.هدایت گاهی به سمت چیزیست که باعث می‌شود آدمی خود را کنار بگذارد و با قبول هر نوع فداکاری و ایثاری به انسان بودن واقعی خود نزدیک شود.معنا درمانی معنا را به سه روش تعریف می‌کند:با انجام دادن کاری ارزشمند و یا خلق و آفرینش آن.به دست آوردن تجربه‌ای حاصل از آشنا شدن با کسی یا چیزی.با تاب آوردن رنج و درد و رویه‌ای که برای آن انتخاب می‌کند.داستان مردی که همسرش مرده بود و مدت‌ها غمناک بود. ازش پرسید اگر تو زودتر مرده بودی، همسرت چه حسی داشت؟یافتن معنایی برای رنج‌ها.به نظر می‌رسه رنج و فنا و پریشانی و مرگ، دزدان معنای زندگی اند، اما چیزی که از دست میره، توانایی‌ها و امکانات هستن. وقتی شکوفا شوند به گذشته‌ای فنا ناپذیر متصل می‌شن، احساس مسئولیت و وظیفه. درس ما از گذرا بودن امکانات و چگونه انتخاب کردن ما: کدام باید شکوفا شود و کدام به فنا برود؟ اثر ماندگار او در این دنیا زودگذر چه خواهد بود؟تقویم اون از نکرده‌ها به کرده‌ها و شده‌ها تبدیل میشه. با افتخار به این برگ‌ها و زندگی پر از فعالیت خود نگاه می‌کند.با جدیت و پشتکار نقش خود را در زندگی بازی کرده است.من بجای امکانات، واقعیات را در کنارم دارم، لبریز از عشق و محبت ورزیده شده و دردها و رنج‌هایی که با دلیری در برابرشون ایستادگی کردم و امروز بیشتر از هرچیزی بهشون افتخار می‌کنم و اجازه نمی‌دم حسرت‌ها در وجودم ریشه کنه.پدری که امکاناتی که خودش فراهم کرده و در اختیار نوجوان‌ها قرار داده.روش متضاد: اتفاقی که ازش ترس داره، با قصد فراوان بخوایش. بر دو پایه استواره:ترس باعث میشه تا همون اتفاقی که ازش می‌ترسیم بیفته.فشار توجه بالا منجر به دور شدن از آنچه آرزو داریم.مثلا آدمی که زیاد عرق می‌کنه و از پیش اومدنش می‌ترسه، هروقت حس کرد عرق می‌کنه، بجای شرمندگی از اطرافیان بخواد ببینن که چقد عرق کرده.حسابداری که از بدخطیش می‌ترسه: بذار همه ببینن چقد خرچنگ غورباقه می‌نویسم، همه باید بدونن.بچه‌ای که لکنت داشت و توی قطار بخاطر بلیط نداشتن، گرفته بودنش و خواسته از لکنتش استفاده کنه. اما اون موقع کاملا واضح صحبت کرده.مگر اینکه خلا وجودی خودنمایی کنه و مجدداً سنتوم‌ها رو فعال کنه.اما شاید آزادی در انتخاب موقعیت‌ها رو گاهی نداشته باشیم. ما آزادی چگونه مواجه شدن با موقعیت‌ها رو داریم.آزادی در کنار مسئولیت پذیری باید باشد.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sun, 18 Aug 2024 10:11:56 +0330</pubDate>
            </item>
                    <item>
                <title>همه چیز درباره سیستم اعتبارسنجی جنگو</title>
                <link>https://virgool.io/@hamze/%D9%87%D9%85%D9%87-%DA%86%DB%8C%D8%B2-%D8%AF%D8%B1%D8%A8%D8%A7%D8%B1%D9%87-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%A7%D8%B9%D8%AA%D8%A8%D8%A7%D8%B1%D8%B3%D9%86%D8%AC%DB%8C-%D8%AC%D9%86%DA%AF%D9%88-lzytwzdywg9g</link>
                <description>به روش‌های متفاوتی میشه توی جنگو پرمیژن‌ها رو تعریف کرد، دو روش اصلی رو اینجا بررسی می‌کنیم:پرمیژن‌ها می‌تونن در سطح model باشن (add, change, delete , view) که اینها به طور پیش‌فرض توسط خود جنگو تعریف میشن و ما می‌تونیم سطح‌های کاستوم دیگه‌ای تعریف کنیم. و در پنل django admin میشه گروه‌بندی تعریف کرد و این سطح دسترسی‌ها رو به گروه‌ها و یا مستقیم به کاربرها داد.خود Django REST Framework هم کلاس‌های پرمیژن خودش رو داره (مثل IsAuthenticated, IsAdminUser) و همینطور ما می‌تونیم کلاس‌های پرمیژن کاستوم DRF رو تعریف کنیم.ساخت سوپر یوزر با کامند:python manage.py createsuperuser --username=joe --email=joe@example.comاحراز هویت کاربر:با نام‌کاربری و پسورد لاگین میشه و یوزر برمی‌گردونه و اگر وجود نداشت None میده:user = authenticate(username=&amp;quotjohn&amp;quot, password=&amp;quotsecret&amp;quot)
# Asynchronous version: aauthenticate()سطح دسترسی:جنگو یک سیستم پرمیژن داخلی داره که باهاش میشه به کاربرها یا گروهی از کاربرها، یک دسترسی خاص داد که از طریق Django admin site انجام میشه. که به این صورته:دسترسی به دیدن ویوها محدود به کاربرهایی که دسترسی view یا change برای اون object ها رو دارن.دسترسی به ویو افزودن فقط به کاربرایی داده میشه که این دسترسی add رو دارن.دسترسی ویرایش، محدود به کاربرایی هست که دسترسی change رو برای اون object ها رو دارن.دسترسی‌ها می‌تونه محدود به ازای هرنوع object نباشه و به ازای یک object خاص باشه. که به کمک متد های زیر انجام میشه:has_view_permission(), has_add_permission(), has_change_permission() and has_delete_permission()مشابه همه جنگو مدل‌ها، از طریق شی کاربر میشه با پرمیژن‌هاش کار کرد:myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()پرمیژن‌ها بعد اولین بار که فراخوانی میشن، کش میشن، و این در بیشتر مواقع اوکیه، اما اگر بخوایم بلافاصله پرمیژن‌های جدید رو بگیریم و کش رو به روز کنیم، آسون‌ترین راه‌حل اینه که دوباره user رو از دیتابیس بگیریم.درباره Proxy model ها:این مدل‌ها دقیقا مشابه مدل معمولی هستن، با این تفاوت که پرمیژن‌هاشون برای خودشونه و ارث نمیبرن:class Person(models.Model):
    class Meta:
        permissions = [(&amp;quotcan_eat_pizzas&amp;quot, &amp;quotCan eat pizzas&amp;quot)]


class Student(Person):
    class Meta:
        proxy = True
        permissions = [(&amp;quotcan_deliver_pizzas&amp;quot, &amp;quotCan deliver pizzas&amp;quot)]

&gt;&gt;&gt; content_type = ContentType.objects.get_for_model(Student, for_concrete_model=False)
&gt;&gt;&gt; student_permissions = Permission.objects.filter(content_type=content_type)چک لاگین بودن کاربر:اگر لاگین نباشه، request.user یک شی از AnonymousUser برمی‌گردونه.if request.user.is_authenticated:
# user = await request.auser() for asyncمحدود کردن بخش‌ها به ورود کاربر:میشه از متد is_authenticated که قبلا گفتیم استفاده کرد.میشه از دکوریتور @login_required استفاده کرد. که اگر لاگین نباشه میفرسته صفحه لاگین.این دکوریتورهم جایی شاید به کارتون بیاد: @staff_member_requiredاستفاده از mixin به نام LoginRequiredMixin در class-based viewsاستفاده از دکوریتور user_passes_test که به عنوان پارامتر اسم یک متد رو میگیره و اگر False برگردونه، کاربر رو می‌فرسته صفحه ریدایرکتی که بهش دادیماستفاده از دکوریتور permission_required که به عنوان پارامتر اسم پرمیژن رو می‌گیره.استفاده از mixin به نام PermissionRequiredMixin برای class-based viewsنامعتبر کردن session بعد از تغییر رمزعبور:به طور معمول در جنگو یک hash در session وجود داره که با هر درخواست کاربر این hash چک میشه که یکسان باشه و اینه که این امکان رو میده که کاربر با تغییر پسوردش، همه از همه session هاش log out بشه. اگر صفجه تغییر پسورد خودتون رو دارین با فراخونی متد زیر، بعد از تغییر پسورد، دیگه کاربر خودش رو لاگ‌اوت نمی‌کنه:update_session_auth_hash(request, form.user)Django REST Framework Permissionsپرمیژن‌ها در REST framework همیشه به صورت لیستی از پرمیژن‌های کلاس تعریف میشن. قبل از اجرای بدنه اصلی view هر پرمیژن توی لیست چک میشه و اگر پرمیژنی ناموفق بشه اکسپشن exceptions.PermissionDenied or exceptions.NotAuthenticated  برمی‌گردونه و کد ویو اجرا نمیشه.دسترسی سطح objectهمینطور دسترسی سطح object هم پشتیبانی میشه که به این صورت میشه چک کردش:obj = get_object_or_404(self.get_queryset(), pk=self.kwargs[&amp;quotpk&amp;quot])
self.check_object_permissions(self.request, obj)مشخص کردن سطح دسترسیمیشه با مشخص کردن DEFAULT_PERMISSION_CLASSES در setting مشخص کرد که سطح پیش‌فرض دسترسی چی باشه.و می‌تونیم سطح دسترسی class-based view ها رو به ازای هر view یا viewset مشخص کنیم:permission_classes = [IsAuthenticated]و یا برای function-based view ها:@permission_classes([IsAuthenticated])در عمل چطور پیاده کنم؟ (روش پیشنهادی)۱- توی پنل ادمین جنگو گروه مورد نظرت رو تعریف کنین و کاربری رو که می‌خوای به این گروه اد کن.۲- کلاس کاستوم پرمیژن رو تعریف کن:from rest_framework.permissions import BasePermission
from django.contrib.auth.models import Group

class IsInGroup(BasePermission):
    group_name = None

    def has_permission(self, request, view):
        return request.user and request.user.groups.filter(name=self.group_name).exists()

class IsInAdminGroup(IsInGroup):
    group_name = &#039;admin&#039;

class IsInEditorGroup(IsInGroup):
    group_name = &#039;editor&#039;

class IsInViewerGroup(IsInGroup):
    group_name = &#039;viewer&#039;۳- توی ویو Group-based پرمیژن رو تعریف کن:from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated, AllowAny

class MyCustomView(APIView):
    permission_classes_by_action = {
        &#039;default&#039;: [IsAuthenticated],
        &#039;retrieve&#039;: [IsInViewerGroup],
        ....
    }

    def get_permissions(self):
        try:
            # Return the permission classes based on the action
            return [permission() for permission in self.permission_classes_by_action[self.request.method.lower()]]
       except KeyError:
            # Return the default permission classes if the action is not explicitly specified
            return [permission() for permission in self.permission_classes_by_action[&#039;default&#039;]]

    def get(self, request, *args, **kwargs):
        # Your GET logic here
        passمنابع:https://docs.djangoproject.com/en/5.0/topics/auth/default/https://www.django-rest-framework.org/api-guide/permissions/#django-rest-framework-role-filters</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Wed, 10 Jul 2024 11:14:54 +0330</pubDate>
            </item>
                    <item>
                <title>همه چی درباره JWT</title>
                <link>https://virgool.io/@hamze/%D9%87%D9%85%D9%87-%DA%86%DB%8C-%D8%AF%D8%B1%D8%A8%D8%A7%D8%B1%D9%87-jwt-hotgf8lkk4mo</link>
                <description>یک نوع توکن اعتبارسنجی که به طور گسترده برای اشتراک اطلاعات بین کلاینت و سرور استفاده میشه. مهمه که توجه داشته باشیم که JWT گارانتی نمی‌کنه که دیتا رمزنگاری شده باشه بلکه encode شده و دیتا توسط هرکسی که رهگیریش کنه، قابل دیدنه، به همین دلیل HTTPS همراه با JWT بسیار پیشنهاد میشه.به یاد داشته باشیم که JWT یک توکن sign شده است نه رمزنگاری شده. پس اطلاعات حساس رو داخلش قرار ندیم.در واقع JWT مخفف JSON Web Token است که یک استاندارد بازه که انتقال اطلاعات JSON، بین دو موجودیت رو امن می‌کنه.یک JWT که sign شده، می‌تونه یکپارچگی اطلاعات داخلش رو ادعا کنه، درحالی‌که یک توکن encrypt شده، می‌تونه مخفی بودن اون اطلاعات رو ادعا کنه. امضای روی توکن امضا شده با public/private key گواهی می‌کنه که فقط کسی که کلید خصوصی رو داره، توکن رو امضا کرده.در پروتوکل‌های stateless، چیزی در مورد درخواست قبلی نمی‌دونه و باید با هر درخواست خودت رو معرفی کنی. اینکه بخوای از session استفاده کنی و کاربر درخواست لاگین بده و بعد یک session id بگیره و با هر درخواست بعدیش بفرسته، راهکار مناسبی نیست، چون این داده session روی سرور ذخیره میشه و حافظه می‌گیره، مدیریت باید بکنیش و session های غیرفعال رو منقضی کنی. هربار باید چک کنی که session معتبر هست یا نه و این کار سربار داره.اما JWT از session استفاده نمی‌کنه، سرور بجای ایجاد session، وقتی کاربر اطلاعات شناسایی شو می‌فرسته، یک JSON Web Token برمی‌گردونه، که باهاش همه کارهایی که نیاز به دسترسی داره رو می‌تونی انجام بدی.مشابه کارت هتله که بعد از رجیستر کردن بهت میدن و باهاش به اتاقت و کافه و استخر و بقیه بخش‌ها دسترسی داری اما به بقیه اتاق‌ها و بخش‌های مدیریتی دسترسی نداری و تاریخ انقضا هم داره.چه زمانی از JWT استفاده کنیم؟اول Authorization: استفاده مرسومش برای اعتبارسنجیه، بعد از لاگین، همه درخواست‌ها با خودشون JWT رو دارن و به کاربر بنا به دسترسی‌هاش، اجازه دسترسی رو میده.دوم انتقال اطلاعات: انتقال امن اطلاعات بین بخش‌ها رو تسهیل می‌کنه. ارسال کننده JWT با امضایی که انجام میده، می‌تونه مشخص بشه، به طور مثال با استفاده از کلید خصوصی و عمومی. همینطور، به دلیل اینکه امضا براساس header و payload محاسبه میشه، می‌تونم تایید کنیم که اطلاعات تغییری داده نشده.مزیت‌های JWTسبک بودنش. از XML encode شده، فضای کمتری نیاز داره.به session نیازی نداره.به طور داخلی expiration داره.به cookie نیازی نداره.ساختار JWTسه بخش اصلی داره که به این شکله: &lt;&lt;header&gt;&gt;.&lt;&lt;payload&gt;&gt;.&lt;&lt;signature&gt;&gt;بخش Header:معمولا دو بخش توی header هست، نوع توکن (JWT) و الگوریتمی که برای امضا شدنش استفاده شده (RSA, HMAC).بخش Payload:این بخش شامل اطلاعاتی که ادعا میشه از سرور اومده. می‌تونه اطلاعات مرتبط با یک موجودیت یا هر اطلاعاتی باشه. ما سه نوع claim داریم که در این قسمت می‌تونیم استفاده کنیم:نوع Registered Claims: از قبل تعریف شده هستن، اجباری نیستن اما امنیت رو بالا می‌برن.iss: issuersub: subjectexp: expiration timenbf: not beforeiat: issued atنوع Public Claims: چیزایی که خود کاربر تعریف می‌کنه و متناسب با اپ هست.نوع Private Claims: مواردی که برای اشتراک اطلاعات بین بخش‌هاس و روش توافق شده و اسامیش توسط توافق طرفین انتخاب شده.بخش SIgnature:برای تولید امضا، لازمه که encoded header و encoded payload و secret رو با الگوریتمی که در header مشخص کردیم sign کنیم.در نهایت از ترکیب این سه بخش، JWT token ما ایجاد میشه.encode64({
   &amp;quotalg&amp;quot: &amp;quotHS256&amp;quot,
   &amp;quottyp&amp;quot: &amp;quotJWT&amp;quot
 }).
encode64({
   &amp;quotsub&amp;quot: &amp;quot1234567890&amp;quot,
   &amp;quotname&amp;quot: &amp;quotJohn Doe&amp;quot,
   &amp;quotadmin&amp;quot: true,
   &amp;quotiat&amp;quot: 1516239022
 }).
HMACSHA256(
   base64UrlEncode(header)
    + &amp;quot.&amp;quot +
   base64UrlEncode(payload),
   your-256-bit-secret
)آسیب‌پذیری‌های معمول JWTدیتای توکن رو تغییر بده و الگوریتم رو  none بزنه (انواع variation کلمه none).کوتاه بودن shared secret برای اینکه سریع باشه، اما باعث میشه حملات brute force آسون‌تر بشه. طول shared secret HS256/384/512  ضروریه.ممکنه اطلاعات payload رو تغییر بدی و به اندپویت بفرستی و در exception برگشتی امضا درست که انتظار داشته رو برگردونه!از طریق پارامتر kid می‌تونه SQL Injection, Path traversal, command injection انجام بده.دستکاری آدرس URL و الگوریتم به روش JWKS Injection/JWKS Spoofingاستانداردهای پیاده‌سازی Best Practicesنوع الگوریتم رو بررسی کنین که None نیاد.ورودی‌های کریپتوگرافیک رو همیشه validate کنین.از کلیدهای رمز قوی استفاده کنین.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Wed, 05 Jun 2024 11:51:56 +0330</pubDate>
            </item>
                    <item>
                <title>در پایتون GIL چیست؟</title>
                <link>https://virgool.io/@hamze/%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-gil-%DA%86%DB%8C%D8%B3%D8%AA-gzqp5f2covel</link>
                <description>فارسیش میشه قفل مترجم جهانی - Global Interpreter Lock - که یک مکانیزم در CPython (پیاده‌سازی پیش‌فرض و پراستفاده‌ترین پایتون) هست که مانع اجرای همزمان بایت کدهای پایتون توسط چندین native thread میشه. برای ساده‌سازی مدیریت حافظه در حضور برنامه‌های چند thread ای در پایتون طراحی شده. برای پیاده‌سازی concurrent programming در پایتون هست.و GIL فقط به یک thread اجازه اجرای بایت‌کد پایتون رو در هر زمان در یک پردازش میده. این یعنی اینکه multiple threads در پایتون نمی‌تونه کد پایتون رو به طور موازی اجرا کنه. (دلیلش اینه که مدیریت حافظه آسون‌تر بشه، از race condition جلوگیری بشه، تغییرات در کد موجود حداقل بشه و...)و GIL در مدیریت دسترسی به آبجکت‌های پایتون و ساختارداده‌ها کمک می‌کنه و از race condition جلوگیری می‌کنه که ممکنه به دلیل اینکه چندین thread بخوان یک دیتای یکسان رو همزمان تغییر بدن ایجاد میشه.و GIL در Jython و ironPython وجود نداره.نمونه کد:import threading

counter = 0

def increment():
    global counter
    for _ in range(1000000):
        counter += 1

# Create two threads to increment the counter
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)
# Start both threads
thread1.start()
thread2.start()

# Wait for both threads to finish
thread1.join()
thread2.join()

# Expected result: The counter will be less than 2,000,000 due to GIL contention
print(&amp;quotCounter:&amp;quot, counter)در این کد دو thread سعی می‌کن که یک شمارشگر مشترک رو اضافه کنن. با توجه به GIL، عملیات افزایش اتمی نیست (چون شامل گام‌های خوندن، افزودن و نوشتن میشه که ممکنه وسطش thread رو سوییچ کنه) و ممکنه منجر به این بشه که مقدار شمارشگر کمتر از مقدار مورد انتظار ۲ میلیون بشه. با کد زیر میشه عملیات افزایش رو اتومیک کرد: از RLock یا Semaphore هم میشه استفاده کرد.with counter_lock:
        # Incrementing the counter within the lock ensures atomicity
        counter += 1باید نسبت به محدودیت GIL آگاه بود. در سناریوهای مرتبط با CPU از مدل‌های همزمانی جایگزین مثل multiprocessing در زمانی که همزمانی واقعی نیاز داریم رو در نظر بگیریم.در سناریوهای مرتبط با I/O، بیایم asynchronous programming رو مدنظر قرار بدیم و از چارچوب‌هایی مثل asyncio برای همزمانی بدون محدودیت‌های GIL استفاده کنیم.در یکسری از کتابخونه‌ها آزاد کردن GIL در سناریوهای مختلف در نظر گرفته شده تا threadهای دیگه بتونن اجرا بشن. این کتابخونه‌ها رو مدنظر قرار بدین.و در نهایت اگر موازی‌سازی براتون حیاتیه، پیاده‌سازی‌های جایگزین پایتون رو مثل Jython و ironPython رو در نظر بگیرین که GIL رو ندارن.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Tue, 28 Nov 2023 16:07:09 +0330</pubDate>
            </item>
                    <item>
                <title>استقرار جنگو - Django Deployment</title>
                <link>https://virgool.io/@hamze/%D8%A7%D8%B3%D8%AA%D9%82%D8%B1%D8%A7%D8%B1-%D8%AC%D9%86%DA%AF%D9%88-django-deployment-aulhqiy4wkwf</link>
                <description>جنگو، یک فریمورک وب هست، پس نیاز به وب‌سرور برای عمل کردن داره و چون اکثر وب‌سرورها به طور نیتیو پایتون نمی‌فهمن، ما نیاز به یک رابط برای ارتباط نیاز داریم.استقرارجنگو در حال حاضر دو رابط رو پشتیبانی می‌کنه:رابط WSGI - web server gateway interface: که استاندارد پایتون برای ارتباط بین وب‌سرور و برنامه‌است. اما فقط کد synchronous رو پشتیبانی می‌کنه. - Gunicorn - Green Unicorn: کار باهاش ساده‌است، از چندین پردازش ورکر پشتیبانی می‌کنه. - uWSGI: پیچیده‌تره و از تنظیمات و کانفیگ‌های مختلفی پشتیبانی می‌کنه و با وب‌سرورهای مختلفی میشه استفاده‌اش کرد.رابط ASGI - Asynchronous Server Gateway Interface: استاندارد جدید asynchronous-friendly هست که به سایت جنگویی امکان استفاده از امکانات غیرهمزمان پایتون و جنگویی که پیاده شده رو میده. موقع استفاده از وب‌سوکت از این رابط‌ها استفاده می‌کنیم. - Daphne: به طور خاص برای اپ جنگو طراحی شده و اگر از channel ها در جنگو استفاده می‌کنین انتخاب مناسبیه. - Hypercorn:  - Uvicorn: معمولا با FastAPI استفاده میشه.شما باید همینطور در نظر بگیرین که چطور فایل‌های static برنامه رو می‌خواین دپلوی کنین و همینطور چطور می‌خواین error reporting رو مدیریت کنین.مدیریت همزمانی - Concurrency - در وب سرورها:رویکرد Eventletدر واقع Eventlet یک concurrent networking library پایتون هست که از  coroutines و greenlets برای دستیابی به همزمانی استفاده می‌کنه. این امکان رو میده که عملیات‌های non-blocking I/O در محیط single-threaded اجرا بشن. درواقع امکان اجرای تعداد زیادی کانکشن به طور همزمان بدون نیاز به multi-threading یا multi-processing رو ایجاد می‌کنه. بر اساس مدل event-driven هست. انتخاب مناسب برای برنامه‌هایی که نیازمند همزمانی بالا و کارایی در هندل کردن تعداد زیادی کانکشن هستن اما از پیچیدگی multi-threading یا multi-processing اجتناب می‌خوایم بکنیم.رویکرد Pre-forkingاین رویکرد شامل ایجاد چندین پروسس قبل از نیاز بهشون برای هندل کردن ریکوئست‌های ورودی میشه. هر پروسس یک نسخه از کد برنامه و منابع برای خودش داره و مستقل عمل می‌کنه. درخواست‌ها بین پروسس‌های در دسترس تقسیم می‌شن و امکان هندل کردن همزمان چندین کانکشن رو ایجاد می‌کنن. ریسک shared state issues وجود نداره، چون هر کدوم منابع مستقل خودشون رو دارن.رویکرد Multi-threadingدر این رویکرد هر کانکشن و درخواست توسط یک thread مجزا هندل میشه. ترد ها به صورت همزمان در یک پروسس اجرا میشن. GIL می‌تونه محدودیت تسک‌های CPU-bound باشه و اما برای تسک‌های I/O-bound کمتر مشکل ایجاد می‌کنه.رویکرد Multi-processingمشابه pre-forking، شامل ایجاد چندین پروسس و هندل کردن به طور همزمان کانکشن‌هاست.رویکرد Asyncioیک کتابخونه پایتون برای نوشتن کد single-threaded concurrent بوسیله coroutines, tasks, and event loops هست. یک چارجوب برنامه نویسی غیرهمزمان میده که اجازه هندل کردن تسک‌های I/O-bound رو بدون استفاده از threads یا processes رو میده.رویکرد Thread Poolingبجای ایجاد یک thread جدید برای هر کانکشن، یک استخر با سایز مشخص از thread ها نگهداری میشه تا درخواست‌های ورودی رو هندل کنن. با این روش سربار ایجاد تعداد زیاد thread برداشته میشه.رویکرد Coroutine Libraries (e.g., Trio, Curio)مشابه asyncio، این کتابخونه‌ها ابزارهایی برای نوشتن asynchronous و concurrent کد بوسیله coroutines در اختیارمون میذارن.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Tue, 28 Nov 2023 16:02:43 +0330</pubDate>
            </item>
                    <item>
                <title>ساختار داده Heap</title>
                <link>https://virgool.io/@hamze/%D8%B3%D8%A7%D8%AE%D8%AA%D8%A7%D8%B1-%D8%AF%D8%A7%D8%AF%D9%87-heap-rbmooy0uepyd</link>
                <description>ساختار داده هیپ یک ساختار داده بر مبنای درخت که به صورت دودویی هست ایجاد شده. یعنی به صورت باینری پیاده سازی میشه در نتیجه پیچیدگی زمانی ایجادش O(log n) خواهد بود. و تمامی شاخه‌ها بجز ردیف آخر که از سمت چپ شروع به پر کردن می‌کنیم، دو فرزند خواهند داشت. کاربرد اصلیش برای پیدا کردن ماکزیمم و مینیموم در لحظه است که پیچیدگی خوندن ماکس و مین با این روش O(1) خواهد بود.دونوع Heap داریم:نوع Max-Heap: کلیدی که در نود روت قرار داره، بزرگترین از بین همه بچه‌ها خواهد بود و همه بچه‌ها کوچکتر و یا مساوی خواهند بود و این قاعده به طور بازگشتی برای همه زیر درخت‌ها برقراره.نوع Min-Heap: کلیدی که در نود روت قرار داره، از همه بچه‌ها کوچکتر یا مساوی خواهد بود و این قاعده برای همه زیر درخت‌ها هم بر قراره.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Fri, 24 Nov 2023 11:20:55 +0330</pubDate>
            </item>
                    <item>
                <title>زبان‌های برنامه‌نویسی از نگاه اجرا، سطح و پردازش</title>
                <link>https://virgool.io/codenevis/%D8%B2%D8%A8%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%A7%D8%B2-%D9%86%DA%AF%D8%A7%D9%87-%D8%A7%D8%AC%D8%B1%D8%A7-%D8%B3%D8%B7%D8%AD-%D9%88-%D9%BE%D8%B1%D8%AF%D8%A7%D8%B2%D8%B4-vnfqyvk2we65</link>
                <description>از جنبه اجرازبان‌های تفسیری (interpreted)در زبان‌های تفسیری (interpreted)، سورس کد مستقیما توسط مفسر اجرا میشه. مفسر کد رو خط به خط می‌خونه و به کد ماشین یا کد میانی تفسیرش می‌کنه و اجراش می‌کنه. هیچ مرحله کامپایل جداگانه‌ای وجود نداره که فایل اجرایی مستقلی ایجاد بشه.زبان‌هایی مثل پایتون، جاوا اسکریپت و روبی، تفسیری هستن.این زبان‌ها به طور کلی انعطاف‌پذیری بیشتری دارن و به پلتفرم وابسته نیستن اما ممکنه در مقایسه با زبان‌های کامپایلری زمان اجرا کندتری داشته باشن.زبان‌های کامپایلری (compiled)در زبان‌های کامپایلری، سورس کد به زبان ماشین یا یک زبان میانی توسط کامپایلر قبل از اجرا ترجمه میشه. کامپایلر کل کد رو آنالیز می‌کنه و یک فایل قابل اجرا که می‌تونه مستقلا اجرا بشه از سورس کد اصلی تولید می‌کنه.زبان‌هایی مثل C, C++, Go و جاوا از این دسته هستن.این زبان‌ها اغلب عملکرد بهتری ارائه میدن چون کد قبل از اجرا بهینه شده. اگرچه گام کامپایل کردن، یک فاز به مراحل توسعه اضافه می‌کنه و توسعه رو می‌تونه کندتر بکنه.زبان‌های کامپایلری اغلب برای هر پلتفرم متفاوت نیازه که دوباره کامپایل بشن تا عملکرد بهینه رو داشته باشن.از جنبه سطحاین مبحث مرتبط با سطح abstraction از سخت‌افزار و میزان خوانایی برای انسان در زبان‌های برنامه‌نویسیه.زبان سطح بالا (High-Level Programming Languages)این زبان‌ها به زبان انسان نزدیک‌تر هستن و abstraction بیشتری از سخت‌افزار دارن که باعث میشه کدهاشون قابل فهم‌تر و خواناتر باشه. معمولا برنامه‌هایی که با زبان‌های سطح بالا نوشته میشن قابل انتقال بیشتر بین پلتفرم‌های متفاوت هستن چون با معماری کامپیتور خاصی گره خورده نیستن.زبان سطح پایین (Low-Level Programming Languages)این زبان‌ها به سخت‌افزار نزدیک‌تر هستن و سطح پایین‌تری از abstraction دارن. در نتیجه نیاز به درک بیشتری از منابع کامپیوتر و معماری‌شون دارن. و همینطور خوانایی‌شون سخت‌تره. اما کنترل بیشتری روی سخت‌افزار دارن و امکان نوشتن کدهای بسیار بهینه و کارا رو میدن، اگرچه به قیمت افزایش پیچیدگی.از جنبه همزمانیاین جنبه اشاره به روشی که زبان برنامه‌نویسی یا فریمورک، اجرای چند تسک یا پردازش رو به طور همزمان مدیریت می‌کنه اشاره داره. یعنی توانایی یک سیستم برای اجرای چندین تسک مستقل به طور همزمان.نوع Sequential Programmingدر این مدل، تسک‌ها یکی پس از دیگری به روش خطی اجرا میشن. یک thread اجرا هر تسک رو به طور متوالی            پردازش می‌کنه.نوع Parallel Programmingدر برنامه‌نویسی موازی، چندین تسک به طور همزمان در لحظه توسط چندین پردازشگر یا هسته اجرا میشن. هر تسک به طور مستقل اجرا میشه.نوع Concurrent Programmingبرنامه‌نویسی همزمان، شامل مدیریت تسک‌های متعدده که ممکنه در دوره‌های زمانی با هم تداخل شروع، اجرا و کامل شدن داشته باشن. این روش برای افزایش پاسخگویی و کارایی در سیستم با چندین تسک و حتی با یک پردازشگر استفاده میشه.نوع Coroutine-Based Concurrencyکوروتین‌ها واحدهای همزمانی سبک و مشارکتی هستن که به تسک‌ها اجازه توقف و از سرگیری رو میدن. بدون سربار thread ها، کانکارنسی رو در اختیارمون می‌ذارن.نوع Thread-Based Concurrency  در این نوع، Threadها واحدهای اجرایی مستقل و سبک در یک پردازش هستن. در این روش، چندین thread به طور همزمان در یک پردازش اجرا میشن. thread ها با هم فضای memory رو به اشتراک می‌ذارن که می‌تونه چالش data synchronization  ایجاد بکنه.نوع Actor-Based Concurrencyهمزمانی مبتنی بر Actor از Actor model الهام گرفته. جایی که اکتور ها موجودیت‌های مستقلی هستن که از طریق ارسال پیام به یکدیگر با هم ارتباط برقرار می‌کنن. هر اکتور وضعیت خاص خودش رو داره و پیام‌ها رو به صورت ناهمزمان پردازش می‌کنه که امکان همزمانی سطح بالایی رو فراهم می‌کنه.نوع Event-Driven Concurrencyبرنامه‌نویسی برمبنای رویداد مبتنی بر اجرای یک رویداد بر اساس trigger شدن اجرای یک تسکه. تسک‌ها معمولا به عنوان یک ایونت هندلر تعریف می‌شن که به یک رویداد خاص پاسخ بدن.در اجراهای همزمان (concurrent) سوییچ کردن بین تسک‌ها در زمان‌های خاصی که به نام context switches اتفاق می‌افته. در این زمان‌ها سیستم‌عامل تصمیم می‌گیره که اجرا رو متوقف کنه و اجرای یک تسک دیگه رو شروع کنه یا ادامه بده. این که دقیقا چه زمانی اتفاق می‌افته مرتبط با مدل همزمانی و سیستم‌عامله. در ادامه یکسری سناریو متداولش رو میگم:زمانی که یک تسک بلاک عملیاتی مثل I/O میشه (خوندن از فایل، صبر برای شبکه) یا به خواب میره.در این مدل هر پردازش زمان مشخصی برای اجرا داره و وقتی که تموم بشه، سیستم‌عامل می‌تونه سوییچ کنه.معماری‌های همزمانی و کتابخونه‌هاش می‌تونن این موضوع رو مدیریت کنن، مثلا در برنامه نویسی مبتنی بر رویداد، این تغییر کانتکست می‌تونه موقع هندل کردن یک رویداد اتفاق بیوفته.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Mon, 13 Nov 2023 20:30:13 +0330</pubDate>
            </item>
                    <item>
                <title>کوبر Kubernetes</title>
                <link>https://virgool.io/@hamze/%DA%A9%D9%88%D8%A8%D8%B1-kubernetes-nz7ysnecrd0v</link>
                <description>کوبر چیه؟یک ابزار اپن‌سورس ارکستریشن (orchestration) هست که توسط گوگل توسعه پیدا کرده و کمک می‌کنه تعداد زیادی اپ کانتینرایز شده (containerized) رو در محیط‌های (environment) مختلف مدیریت کنیم.مشکلی که حل می‌کنه اینه که وقتی از سمت منولوتیک به سمت میکروسرویس میری، به راهکاری نیاز داری که به روش درست و مناسبی بتونی صدها کانتینر رو مدیریت کنی، به این کار میکنم ارکستریشن.کاری که برات میکنه اینه که:بهت high availability رو میده و کمک می‌کنه downtime نداشته باشی.بهت عملکرد بالا و scalibility رو میده. موقع نیاز، زیرساخت رو scale می‌کنه و هر زمان لازم نبود دوباره کاهشش می‌ده.بازیابی فاجعه‌ها: اگر هر مشکلی برای زیرساخت یا دیتاسنتر پیش بیاد، سازکاری برای بک‌آپ و بازیابی اطلاعات داره.معماری کوبر:حداقل یک Master Node که بهش Control Plane می‌گیم و چندین Worker Node که بهشون Nodes می‌گیم، تشکیل شده.هر نود روش kubelet process ران شده، که کارش اینه که امکان ارتباط کلاستر با هم رو ایجاد کنه و یکسری تسک مثل اجرای برنامه رو انجام بده. هر ورکر نود روش چندین کانتینر اپ دپلوی شده و اینجا جایی که برنامه‌تون داره اجرا میشه.روی مسترنود برنامه‌هایی که برای اجرای درست و مدیریت کلاستر لازمه اجرا میشه. که شامل این موارده:بخش API Server: نقطه ورود به کلاستر کوبر، داشبورد و API و کامندلاین با این قسمت مرتبط میشه.بخش Controll Manager: کلیت اینی که در کلاستر وضعیت چیه رو نگه میداره. اینکه یک کانتینر مرده و نیازه بازیابی بشه و... بخش Scheduler: این بخش تصمیم می‌گیره که روی کدوم نود، پاد (کانتینر) جدید باید بالا بیاد بر اساس منابعی که اون کانتینر نیاز داره و منابعی که در اون نود موجوده.بخش etcd: استوریج key value، وضعیت هر لحظه کلاستر کوبر رو نگه میداره. همه دیتای تنظیمات رو داره. بخش بک‌آپ و بازیابی که صحبت کردیم هم براساس اسنپ‌شات‌هات این قسمت انجام میشه. بخش VIrtual Network: کارش اینه که همه نودها رو تبدیل به یک ماشین unified بکنه و امکان صحبت کردن مستر نود و ورکر نودها رو فراهم کنه. توجه داشته باشیم که لود اصلی روی ورکرهاست، پس منابع بیشتری دارن. مستر نود هم چون همه کارهای مدیریتی رو انجام میده و اگر مشکل بخوره، کل کلاستر غیر قابل استفاده میشه، لازمه که حداقل یک سرور بک‌آپ ازش داشته باشیم.کامپوننت‌های اصلی کوبر:بخش node: یک سرور فیزیکی یا مجازیبخش pod: کوچک‌ترین کامپوننت کوبر هست. معمولا شامل یک کانتینر میشه. هر پاد یک ip آدرس داره و می‌تونن باهم صحبت کنن که این آدرس داخلیه و از طریق virtual network در اختیارشون قرار گرفته. پادها ephemeral هستن، این یعنی می‌تونن خیلی راحت بمیرن، و اگر این اتفاق بیوفته، یک جدیدش ایجاد و جایگزین میشه و ip آدرس جدید می‌گیره، اگر برای ارتباط برنامه با دیتابیس از ip استفاده کرده باشیم به مشکل می‌خوریم برای همین از کامپوننت دیگه‌ای به نام service استفاده می‌کنیم.بخش Service: سرویس یک ip آدرس ثابته که می‌تونه به هر پاد تخصیص پیدا کنه. برای اینکه بخوایم اپ رو توی مرورگر باز کنیم نیاز به اکسترنال سرویس داریم، اکسترنال سرویس امکان دسترسی از طریق سرویس‌های بیرونی رو بهمون میده. اما برای دیتابیس نمی‌خوایم این دسترسی وجود داشته باشه، پس از اینترنال سرویس استفاده می‌کنیم. بخش Ingress: وقتی بخوایم از اکسترنال سرویس استفاده کنیم، باید ip نود و پورتش رو بزنیم، اما ما می‌خوایم که از یک پروتکل امن و نام دامنه استفاده کنیم. این کار رو Ingress برامون می‌کنه. درخواست اول به اینگرس میره و بعد از اونجا فوروارد میشه به سرویس. کامپوننت ConfigMap: فرض کنین که آدرس دیتابیس عوض شده، باید بری تو کدت عوض کنی، بعد build بگیری و بعد پوش کنی روی repo و بعد روی پاد pull بگیری! این برای همچین تغییر کوچیکی زیاده. در واقع کانفیگ‌مپ، تنظیمات بیرونی اپلیکیشن‌تونه که کانفیگ‌ها رو نگه میداره و پاد می‌تونه دیتا رو ازش بگیره. توجه داشته باشین که در کانفیگ‌مپ فقط دیتای غیرامنیتی رو بذارین.کامپوننت Secret: کامل مشابه ConfigMap هست با این تفاوت که برای نگهداری دیتاهای امنیتی مثل پسوردها هست و به صورت encode base 64 نگهداری میشه. به طور پیشفرض رمزگذاری نشده و باید خودتون کانفیگ کنینش.کامپوننت Volume: با رستارت پاد دیتابیس دیتاش میپره و این چیزی که ما می‌خوایم نیست. با استفاده از volume بخشی از حافظه فیزیکی روی هارد به پاد اختصاص داده میشه که می‌تونه روی لوکال ماشین و یا خارج از کلاستر کوبر باشه. کوبر کار مدیریت ماندگاری دیتا رو انجام نمیده، ما مسئول اینیم که مطمئن بشیم که رپلیکا و بکاپ و... برای اون دیتا داریم. در کوبر همه چیز replica دارن، یعنی یک نسخه دیگه ازشون موجوده، اینطور وقتی اپ به هر دلیلی بیاد پایین، کاربر با downtime روبرو نمیشه. رپلیکا ها به یک سرویس متصل هستن، سرویس همینطور یک لودبالانسر هم هست، این یعنی درخواست رو دریافت می‌کنه و پادی میفرسته که کمتر سرش شلوغه. برای این که رپلیکا داشته باشیم باید یک blueprint برات پادها تعریف کنیم که توش مشخص کنیم که چه تعداد رپلیکا می‌خوایم داشته باشیم. به این بلو پرینت میگیم deployment.کامپوننت deployment: در واقع abstraction ای از پاد هاست که رپلیکا کردن و تنظیمات دیگه‌ای مثل scale up یا scale down کردنشون رو انجام میده. در عمل ما غالبا با دپلویمنت کار می‌کنیم و نه پادها.  اما ما دیتابیس رو با دپلویمنت نمی‌تونیم مدیریت کنیم چون state داره، یعنی اینکه نیاز به دسترسی به یک دیتا استوریج مشترک داره. و نیاز به یک مکانیزم داریم که مشخص کنه کدوم پاد داره می‌نویسه و کدوم پاد داره ازش می‌خونه تا از ناهماهنگی داده جلوگیری کنه. این مکانیزم همراه با قابلیت رپلیکا توسط Statefulset در اختیارمون قرار می‌گیره.کامپوننت statefulset: این کامپوننت برای اپ‌های stateFUL ای مثل دیتابیس‌ها به کار میره. دپلوی statefulset ها آسون نیست، برای همین  یک پرکتیس معمول اینه که دیتابیس رو خارج از کلاستر کوبر هاست می‌کنن.کانفیگ کوبراز طریق API Server که قبلا صحبت شد، ما کانفیگ‌ها رو در فرمت YAML و یا Json به کوبر میدیم. سه بخش اصلی این فایل کانفیگ داره:متادیتا (metadata): که نام کامپوننت هستمشخصات (specification): همه مشخصاتی که می‌خوایم روی اون کامپوننت اعمال بشه. وضعیت (status): این بخش اتومات توسط کوبر ایجاد و اضافه میشه. کوبر همواره چک می‌کنه که وضعیت موجود چیه و وضعیت مورد نظر ما چیه، اگر یکی نباشن، کوبر میره و حلش می‌کنه. اطلاعات وضعیت موجود از etcd میاد.راه اندازی لوکالو minikube چیه؟اگر ما بخوایم کل کلاستر پروداکشن رو روی ماشین لوکال‌مون ران کنیم، سیستم‌مون قاعدتا جواب نمیده. برای همین از minikube استفاده می‌کنیم. این‌طور یک نود داریم که روش هم Master processes و هم Worker Processes ران میشه و روش داکر کانتینر نصبه. خب برای راه‌اندازیش ما از kubectl استفاده می‌کنیم.و kubectl چیه؟ابراز کامندلاین (CLI) برای کلاستر کوبر هست. توجه داشته باشین که kubectl فقط برای کار با Minikube cluster نیست و با همین ابزار با همه نوع کلاستر کوبر میشه کار کرد. از سایت minikube نصبش می‌کنیم. اتفاقی که می‌افته ما خود minikube رو با داکر ران می‌کنیم و داخل خودش باز با داکر ران میشه اپ (آپشن ران با virtual machine رو هم داریم). پس اگر داکر ندارین، اون رو هم نصب کنین.ران کردن کوبر با درایور داکر:minikube start --driver dockerچک وضعیت کلاستر:minikube statusنمایش همه نود های داخل کلاستر:kubectl get nodeنمایش همه پادها:kubectl get podدستور اعمال فایل‌های yaml پیکربندی:kubectl apply -f [mongo-config.yaml]گرفتن تمام کامپوننت‌های داخل کلاستر:kubectl get allگرفتن  کانفیگ‌مپ و سکرت‌های کوبر:kubectl get secret
kubectl get configmapجزئیات یک کمپوننت:kuectl describe pod [pod-name]چک کردن لاگ‌های یک پاد:kubectl logs [pod-name] -fگرفتن minikube IP:minikube ipنمونه کانفیگ یک پروژه کوبر ساده:https://gitlab.com/nanuchi/k8s-in-1-hour</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Fri, 10 Nov 2023 15:22:25 +0330</pubDate>
            </item>
                    <item>
                <title>دیزاین پترن‌های مرتبط با دیتابیس</title>
                <link>https://virgool.io/@hamze/%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D9%BE%D8%AA%D8%B1%D9%86-%D9%87%D8%A7%DB%8C-%D9%85%D8%B1%D8%AA%D8%A8%D8%B7-%D8%A8%D8%A7-%D8%AF%DB%8C%D8%AA%D8%A7%D8%A8%DB%8C%D8%B3-dvpqdigwwx2r</link>
                <description>در ارتباط با سروکله زدن با دیتابیس، الگوهای متفاوتی وجود داره که چند مورد اصلیش رو بررسی می‌کنیم:الگو اکتیو رکورد (Active Record Pattern):روش ساده‌ای که در اکثر فریمورک‌ها می‌بینیم، به این صورت که رکورد دیتابیس رو به صورت آبجکت در اختیار ما می‌گذاره و به کمک متدها می‌تونید باهاش کار کنیم. کار کردن باهاش ساده‌ است و پیاده‌سازی ساده‌ای هم داره.  اما ضعفش اینه که دیتاها و لاجیک درهم‌آمیخته (coupling) میشن.new_user = User(None, &#039;john_doe&#039;, &#039;john@example.com&#039;)
new_user.save()الگو ریپوزیتوری (Repository Pattern):این الگو، منطق دسترسی به داده‌ها رو از بقیه اپلیکیشن جدا می‌کنه و در سطح بالاتری کار با دیتابیس رو ارائه میده. به این صورت پیاده میشه که کار با دیتابیس رو ابسترکت (abstracts) میکنه و به صورت یک اینترفیس (interface) تعریف میشه و اون اینترفیس پیاده سازی و ازش استفاده میشه. با این کار تست‌پذیری، انعطاف‌پذیری و امکان راحت استفاده از دیتابیس‌ها متفاوت رو پیدا می‌کنیم. اما از طرفی پیچیدگی پیاده‌سازی رو بیشتر می‌کنه. در واقع لاجیک بیزینس کاری نداره که اون سمت دیتابیس چه دیتابیسی قرار داره و چطور کار می‌کنه و فقط با ابسترکتش سر و کار داره.الگو دیتا مپر (Data Mapper Pattern):این الگو یک لایه برای مجزا کردن آبجکت توی مموری (که نمایانگر داده دیتابیسته، مثلا آبجکت User) از الگو دیتابیس  مربوطه‌اشه (که شامل جداول و ستون‌ها و ارتباط‌های جداول و محدودیت‌هاشونه). استفاده اصلیش اینه که دسترسی به داده و ارتباطش با دیتابیس رو از لاجیک مربوط به برنامه جدا کنه. این الگو باعث میشه لاجیک بیزینس از کد دسترسی دیتابیس جدا کرد. اما خب پیچیدگی پیاده‌سازی رو بیشتر می‌کنه. مثالش:class UserMapper {
    public function findById($id) {
        // Database query and mapping logic here
    }
    
    public function save(User $user) {
        // Database save logic here
    }
}الگو یونیت آف ورک (Unit of Work Pattern):این الگو معمولا در مورد چارچوب object-relational mapping (ORM) به کار میره، کمک می‌کنه که تراکنش‌ها (transactions) و عملیات‌های مرتبط با چرخه‌حیات دیتابیس رو  به صورتی مدیریت کنیم که مطمئن بشیم دیتا بی‌نقص و کامله، هدف اصلیش اینه که چندین عملیات دیتابیس در یک تراکنش انجام بشه و مطمئن بشیم که همه تغییرات یا کامیت میشه و یا همه به حالت قبل برمی‌گردن (roll back).class UnitOfWork:
    def __init__(self, database):
        self.database = database
        self.connection = None

    def __enter__(self):
        self.connection = sqlite3.connect(self.database)
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            self.connection.commit()
        else:
            self.connection.rollback()
        self.connection.close()

# Example usage
with UnitOfWork(&#039;mydb.db&#039;) as uow:
    cursor = uow.connection.cursor()
    cursor.execute(&#039;INSERT INTO users (name, email) VALUES (?, ?)&#039;, (&#039;John Doe&#039;, 
john@example.com&#039;))
    cursor.execute(&#039;UPDATE users SET name = ? WHERE id = ?&#039;, (&#039;Updated Name&#039;, 1))الگو کوئری آبجکت (Query Object Pattern):از این الگو برای این استفاده میشه که یک کوئری رو در یک آبجکت قرار بدیم که یکسری پارامتر بگیره و به طور مستقل اجرا بشه. با این کار یکسری کوئری قابل استفاده در جاهای متفاوت داری که نگهداری و تغییرات آینده رو هم راحت‌تر می‌کنه.class UserQuery:
    def __init__(self, db):
        self.db = db
        self.query = &amp;quotSELECT * FROM users WHERE age = :age&amp;quot

    def execute(self, age):
        # Execute the query with the provided age parameter
        cursor = self.db.cursor()
        cursor.execute(self.query, {&#039;age&#039;: age})
        return cursor.fetchall()الگو تیبل دیتا گت‌اوی (Table Data Gateway Pattern):توی این الگو میایم و به ازای هر جدول دیتابیس یک کلاس مشخص تعریف می‌کنیم و عملیات‌های دسترسی به داده‌اش رو تعریف می‌کنیم.class UserGateway:
    def __init__(self, db_connection):
        self.db_connection = db_connection

    def find_by_id(self, user_id):
        pass

    def create_user(self, name, email):
        pass

    def update_user(self, user_id, name, email):
        pass

    def delete_user(self, user_id):
        passالگوی آبجکت دسترسی به داده (Data Access Object (DAO) Pattern):این الگو هم میاد و یک اینترفیس (interface) برای عملیات‌های دیتابیس تعریف می‌کنه. درواقع میشه گفت ترکیبی از الگوهایی مثل Repository و Unit of Work می‌تونه باشه. ولی Repository معمولا سطح بالاتره و با نگاه به منطق بیزینس تعریف میشه، مثلا متدهایی مثل findUserById, getProductByName, or saveOrder اما در DAO می‌تونه سطح پایین‌تر و در ارتباط نزدیک‌تر با دیتابیس و همینطور متدهای کلی‌تر مثل executeQuery, insertRecord, or updateData باشه.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Tue, 07 Nov 2023 01:22:26 +0330</pubDate>
            </item>
                    <item>
                <title>مفاهیم امنیت و دستکاری داده نرم‌افزار که باید فرقشون بدونیم</title>
                <link>https://virgool.io/@hamze/%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-%D8%A7%D9%85%D9%86%DB%8C%D8%AA-%D9%88-%D8%AF%D8%B3%D8%AA%DA%A9%D8%A7%D8%B1%DB%8C-%D8%AF%D8%A7%D8%AF%D9%87-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%DA%A9%D9%87-%D8%A8%D8%A7%DB%8C%D8%AF-%D9%81%D8%B1%D9%82%D8%B4%D9%88%D9%86-%D8%A8%D8%AF%D9%88%D9%86%DB%8C%D9%85-kvxxgh3xmdn0</link>
                <description>معنی Encode کردن:به پروسه تبدیل کردن داده از یک فرمت به فرمت دیگه می‌گن. موقع encode کردن دنبال امنیت نیستیم چون غالبا یک فرآیند برگشت‌پذیره، یعنی می‌تونی decode بکنیش تا به فرم اصلیش برگرده. اسکیماهای متداول encode کردن این موارده: Base64, URL encoding, HTML encodingمعنی Encrypt کردن:به فرآیند تغییر داده به فرمت امن و غیرقابل خوندن به کمک الگوریتم encryption و یک key می‌گن. دلیل اصلیش، حفاظت از داده‌های محرمانه است. فقط کسانی که به کلید decryption دسترسی دارن، می‌تونن به داده اصلی دسترسی پیدا کنن. الگوریتم‌های encryption شامل AES, RSA, DES میشه و ازشون معمولا برای امن کردن دیتاهای حساس مثل اطلاعات کارت اعتباری و داده‌های شخصی در طی انتقال داده یا ذخیره‌سازی استفاده میشه.معنی Hash کردن:هش کردن پروسه گرفتن یک ورودی یا پیام و برگردوندن یک رشته از کاراکترهای با طول مشخص هست که معمولا اعداد هگزادسیمال هستن. عملیات هش یک عملیات یک طرفه است، یعنی به سادگی نمیشه پروسه رو معکوس کرد تا به ورودی اولیه هش برسی. هش معمولا برای اعتبارسنجی و تایید صحت اطلاعات استفاده میشه. برای بررسی اینکه آیا داده‌ها دستکاری شده‌ان مفیدن چون هر تغییری در ورودی منجر به تولید یک هش کاملا متفاوت میشه. فانکشن‌های هش مرسوم: MD5, SHA-1, SHA-256 هستن.معنی Compression کردن:به معنی پروسه کاهش دادن سایز داده برای اینکه فضای ذخیره سازی کمتری بگیره و یا کارایی انتقال داده رو افزایش بده. این معمولا یک فرآیند برگشت پذیره و می‌تونی داده رو Decompress کنی تا به حالت اولش برگرده.معنی Salting کردن:سلتینگ تکنیکی که در هش کردن استفاده میشه تا امنیت پسوردهای هش شده رو افزایش بده. یک مقدار رندوم (salt) به پسورد قبل هش کرد اضافه میشه که باعث میشه چالش بیشتری برای اتکرها ایجاد بشه که از جدول‌های از پیش‌محاسبه شده (rainbow tables) برای شکستن پسوردها استفاده کنن. به طور مثال برای هش کردن پسورد کاربران به ازای هر یوزر باید از salt یکتایی استفاده کرد.معنی Tokenization کردن:به پروسه جایگزین کردن اطلاعات حساس با شناسه منحصر به فرد (unique identifier or token) می‌گن. دیتای اصلی امن نگهداری میشه و فقط توکین در سیستمی که به صورت پابلیک هست استفاده میشه تا دردسترس بودن اطلاعات حساس رو کاهش بده.در ادامه میخوام درباره مفاهیمی که در مواردی که صحبت کردیم به کار میره کمی بیشتر دقیق بشم:کلید (key) چیه؟کلید بخشی از اطلاعاته که در الگوریتم‌های رمزنگاری (cryptographic) استفاده میشه تا پروسه رمزگذاری و رمزگشایی رو کنترل کنه و برای این پروسه وجودش ضروریه. دو نوع داره:متقارن (symmetric): در رمزنگاری متقارن، یک کلید واحد برای رمزنگاری و رمزگشایی استفاده میشه.نامتقارن (asymmetric): در رمزنگاری نامتقارن، معمولا یک جفت کلید وجود داره، یکی برای رمزنگاری (public key) و دیگری برای رمزگشایی (private key).نمک (salt) چیه؟رندوم دیتایی که تولید و اضافه میشه به ورودی برای توابع رمزگذاری هش، معمولا در کانتکس هش‌کردن پسورد به کار میره تا امنیت پسورد هش شده رو افزایش بده. با salt مطمئن میشیم که حتی اگر دو کاربر رمز یکسانی رو به‌کار ببرن، مقدار هش‌شده شون یکی نخواهد بود.فلفل (pepper) چیه؟مشابه salt و یک دیتای رندومه اما به صورت متفاوتی استفاده میشه، معمولا یک مقدار محرمانه‌ است که جدا از دیتای هش‌شده نگهداری میشه. به داده قبل از هش شدن اضافه میشه اما در دیتابیسی که مقدار هش‌شده نگهداری میشه، نگهداری نمیشه. هدفش اینه که یک لایه دیگه امنیت اضافه کنه و اگر مهاجم‌ها به داده هش‌شده دسترسی پیدا کردن، کار رو براشون سخت‌تر کنه.</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sun, 05 Nov 2023 15:49:21 +0330</pubDate>
            </item>
                    <item>
                <title>رویارویی با الگوریتم‌های گراف</title>
                <link>https://virgool.io/@hamze/%D8%B1%D9%88%DB%8C%D8%A7%D8%B1%D9%88%DB%8C%DB%8C-%D8%A8%D8%A7-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85-%D9%87%D8%A7%DB%8C-%DA%AF%D8%B1%D8%A7%D9%81-pg9g0xr0jap9</link>
                <description>الگوریتم‌های گراف جدا از این که در محاسبه‌های الگوریتمی چالش می‌تونن ایجاد کنن، در خیلی از کسب و کارها مثل مسیریابی، شبکه‌های اجتماعی و... کاربردی هستن. با یک رویکرد درست و فهم کانسپت‌های اصلی میشه از پسشون براومد. در ادامه درباره گام‌های حل مسائل گراف رو بررسی می‌کنیم:(این مقاله به مرور کامل‌ خواهد شد)۱- فهم مساله:اول سعی کنیم مساله رو به درستی متوجه بشیم.محدودیت‌های مساله، فرمت ورودی و فرمت مورد انتظار خروجی رو مشخص کنیم.۲- مساله رو به صورت گراف مدل‌سازی کنیم:مشخص کنیم که آیا مساله می‌تونه به صورت گراف نمایش داده بشه. خیلی از مسائل دنیای واقعی رو میشه به صورت گراف، مپ کرد.شناسایی نودها (nodes - vertices) و لبه‌ها (edges) که مرتبط با مساله هستنمشخص کردن نوع گراف: جهت‌دار یا بدون جهت (directed or undirected)ُ، وزن‌دار یا بدون‌وزن (weighted or unweighted)ُ، چرخه‌دار یا بدون چرخه (cyclic or acyclic)۳- انتخاب الگوریتم گراف مناسب:براساس مساله، لازمه که از الگوریتم مناسب برای حل استفاده کنیم:Depth-First Search Breadth-First Search Dijstra&#x27;s Algorithm (Shortest Path) Bellman-Ford Algorithm (shortest path with negative weights)Kruskal&#x27;s Algorithm (minimum spanning tree)Prim&#x27;s Algorithm (minimum spanning tree)Floyd-Warshall Algorithm (all pairs shortest paths)Topological Sort (for directed acyclic graphs)Strongly Connected Components (SCC)۴- پیاده‌سازی الگوریتم و تستش با ورودی‌های مختلف و بهینه‌سازی در صورت نیاز۵- بررسی پیچیدگی زمانی و فضایی (Time and Space Complexity)۶- فهم انواع سوالات مثل: finding paths, cycles, minimum spanning trees, and topological sorting۷- آشنایی با مفاهیم مشترک گراف‌ها مثل: vertices, edges, adjacency matrices, and adjacency lists۸- آشنایی با ساختار داده‌های مرتبط: queues, stacks, and priority queues</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Tue, 24 Oct 2023 15:03:36 +0330</pubDate>
            </item>
                    <item>
                <title>حل مسائل داینامیک پروگرمینگ Dynamic Programming</title>
                <link>https://virgool.io/@hamze/%D8%AD%D9%84-%D9%85%D8%B3%D8%A7%D8%A6%D9%84-%D8%AF%D8%A7%DB%8C%D9%86%D8%A7%D9%85%DB%8C%DA%A9-%D9%BE%D8%B1%D9%88%DA%AF%D8%B1%D9%85%DB%8C%D9%86%DA%AF-dynamic-programming-ec9epf62locj</link>
                <description>داینامیک پروگرمینگ به طور عمده، بهینه سازی مثایل بازگشتیه (Recursion). راه‌حل‌های بازگشتی رو به این روش ما می‌تونیم بهینه کنیم. ایده به این صورته که نتیجه زیرمساله‌ها رو یک جایی ذخیره کنیم، در نتیجه بعدا که بهشون نیاز داریم، لازم نیست که دوباره حساب‌شون کنیم. این راهکار، پیچیدگی زمانی رو از تصاعدی به چندجمله‌ای (exponential to polynomial) تبدیل می‌کنه.تکنینک‌های حل مسائل داینامیک پروگرمینگ:۱- رویکرد بالا به پایین (Top-Down): این رویکرد از تکنیک memoization استفاده می‌کنه که شامل recusrsion و caching هست. بازگشتی، فرآینده فراخوانی پی‌درپی تابع‌هاست و کش کردن، پروسه ذخیره نتایج میانی هست.۲- رویکرد پایین به بالا (Bottom-Up): این رویکرد از تکنیک tabulation استفاده می‌کنه که راهکار داینامیک پروگرمینگ رو پیاده‌سازی می‌کنه. به روش قبلی مساله رو حل می‌کنه ولی بدون بازگشتی (recursion). در این روش حلقه جایگزین بازگشتی میشه. نمونه کد حل مساله فیبوناچی به روش memoization:def fibonacci(n, cache={}):
    if n in cache:
        return cache[n]
    if n == 0:
        result = 0
    elif n == 1:
        result = 1
    else:
        result = fibonacci(n-1) + fibonacci(n-2)
    cache[n] = result
    return resultنمونه کد حل مساله فیبوناچی به روش tabulation:int fibonacci(int n) {
    if (n == 0) {
        return 0;
    } else if (n == 1) {
        return 1;
    } else {
        std::vector&lt;int&gt; table(n + 1, 0);
        table[0] = 0;
        table[1] = 1;
        for (int i = 2; i &lt;= n; i++) {
            table[i] = table[i-1] + table[i-2];
        }
        return table[n];
    }
}</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sun, 22 Oct 2023 15:05:32 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از Celery در پایتون</title>
                <link>https://virgool.io/@hamze/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-celery-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-g2enza5lccmh</link>
                <description>از سلری برای انجام یک سری task به صورت Async استفاده میشه. یعنی کد متوقف انجام شدن تسک نشه.برای استفاده ازش نیاز به یک Task Queue داری که می‌تونی مثلا از RabbitMQ استفاده کنی (میشه از Redis و یا سرویس‌هایی مثل Amazon SQS استفاده کرد). من چون نمی‌خواستم روی local machine ام نصب کنم، از این سایت برای ایجادش استفاده کردم:https://www.cloudamqp.comگام‌های راه اندازیش:انتخاب و نصب یک انتغال‌دهنده پیام (broker)نصب سلری و ایجاد اولین تسکراه‌اندازی worker و فراخوانی تسک‌هاردگیری تسک‌ها در طی تغییر وضعیت‌شون و بررسی پاسخ برگشتی‌شونبرای نصب سلری از دستور زیر استفاده می‌کنیم:pip install celeryحالا یک فایل برای راه اندازی سلری ایجاد می‌کنیم:from celery import Celery
# first argument is the name of module, 2nd is broker URL
app = Celery(&#039;tasks&#039;, broker=&#039;pyamqp://guest@localhost//&#039;)

@app.task
def add(x, y):
    return x + yبرای راه‌اندازی worker از دستور زیر استفاده می‌کنیم:celery -A tasks worker --loglevel=INFOتوی پرداکشن worker رو لازمه در background ران کنیم.برای فراخوانی یک تسک از دستور زیر استفاده می‌کنیم:from tasks import add
add.delay(4, 4)اگر بخوایم وضعیت‌های سلری رو track کنیم و نتایج رو نگه‌داریم، باید یکجا نگهداری بشن که آپشن‌هایی مثل SQL, Mongo, Memcached, Redis, PRC یا هر روشی که خودت تعریف کنی رو داری.فرض کن که می‌خوای از Redis استفاده کنی، کدش به این صورت خواهد شد:app = Celery(&#039;tasks&#039;, broker=&#039;pyamqp://guest@localhost//&#039;, backend=&#039;redis://localhost&#039;)</description>
                <category>حمزه قائم پناه</category>
                <author>حمزه قائم پناه</author>
                <pubDate>Sat, 21 Oct 2023 15:36:14 +0330</pubDate>
            </item>
            </channel>
</rss>