<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های Masoud Kheradmandi</title><link>https://virgool.ir/feed/@kheradmandimasoud416</link><description>من امیرمسعود خردمندی هستم  Backend Developer</description><language>fa</language><pubDate>2026-11-10 19:45:56</pubDate><image><url>https://files.virgool.ir/upload/users/3222159/avatar/TID2fi.jpg</url><title>Masoud Kheradmandi</title><link>https://virgool.ir/@kheradmandimasoud416</link></image><item><title>nmap چیه؟</title><link>https://virgool.ir/@kheradmandimasoud416/nmap-چیه-qbnylx3jshtk</link><description>خیلی راحت و ساده بگم یه ابزار اوپن سورسه برای اسکن کردن ایپی و پورت و تشخیص اینکه چه برنامه هایی نصب هستناسکن پورتاسکن پورت که خب تکلیفش خیلی مشخصهچه پورت هایی روی سرور بازن؟مثلا پستگرس 5432 ردیس 6379بهمون میگه این پورت های ip مورد نظر بازهدستورش؟nmap 192.168.1.10خروجی:22/tcp   open   ssh&#xA;80/tcp   open   http&#xA;443/tcp  open   httpsحالا اسکن کردن ip چیه؟شاید گیج بشین که ینی چی اسکن کردن IPهیچی عزیز من:)داره میگه چه ایپی هایی در این شبکه قابل دسترسندستورش؟nmap -sn PRIVATE_IP/24خروجی اش چی میشه؟Nmap scan report for 192.168.1.1&#xA;Host is up&#xA;&#xA;Nmap scan report for 192.168.1.5&#xA;Host is up&#xA;&#xA;Nmap scan report for 192.168.1.20&#xA;Host is upمثلا برای خودم گوشی و لپتاپ و سیستمم رو اوورد (همشون به مودمم وصلن)اون 24 اخر هم یادتون نره بزارین —&gt; بعدا توضیح میدم چیه :)تشخیص برنامه هایی که نصب هستن چیه؟چیزی که من متوجه شدم بعد از تشخیص پورت ها با دستور اولحدس میزنه چه اپ هایی نصب هستن روی سرور و قرار نیست اگه میگه مثلا postgresql رو تشخیص نداده قطعا اون وجود ندارهصرفا پورتش بسته اسمثلا روی سایت بنده خدایی همینجوری تست گرفتم ,امیدوارم حلال کنه :), نتیجه اش این بودهnmap brsapi.ir&#xA;Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-09-20 22:09 +0330&#xA;Nmap scan report for brsapi.ir (185.206.229.81)&#xA;Host is up (0.033s latency).&#xA;rDNS record for 185.206.229.81: bita.mahanserver.net&#xA;Not shown: 900 filtered tcp ports (no-response), 1 filtered tcp ports (host-unreach), 88 closed tcp ports (conn-refused)&#xA;PORT    STATE SERVICE&#xA;21/tcp  open  ftp&#xA;25/tcp  open  smtp&#xA;53/tcp  open  domain&#xA;80/tcp  open  http&#xA;110/tcp open  pop3&#xA;143/tcp open  imap&#xA;443/tcp open  https&#xA;465/tcp open  smtps&#xA;587/tcp open  submission&#xA;993/tcp open  imaps&#xA;995/tcp open  pop3s&#xA;&#xA;Nmap done: 1 IP address (1 host up) scanned in 154.00 secondsمن مسعود هستم و اگه از این مقاله خوشتون اومد برای دوستاتون هم بفرستین</description><category>Masoud Kheradmandi</category><author>Masoud Kheradmandi</author><pubDate>Sun, 18 Oct 2026 11:21:27 +0330</pubDate></item><item><title>وقتی SQLAlchemy دیتای قدیمی را به ما برگرداند</title><link>https://virgool.ir/@kheradmandimasoud416/وقتی-sqlalchemy-دیتای-قدیمی-را-به-ما-برگرداند-m0fbrfdsr8ij</link><description>یه اتفاق خیلی عجیب برای ما توی پروداکشن افتاد که ساعت یک شب برای بخش خرید ارور 500 گرفتیم.حالا موضوع چی بود؟فروشگاه ما به این شکل بود که محصولات از طریق یه Provider آپدیت موجودی و قیمت میشدن. تقریباً آپدیت هر محصول 5 ثانیه طول میکشید.ما توی فروشگاهمون یه سری محصولات خیلی ارزون هم داشتیم که کمتر از چند سنت بودن و هفته‌ای یک یا دوبار شارژ میشدن.یه فیچری هم زده بودیم که مشتری‌هامون میتونستن بگن:هر موقع این محصول موجود شد برامون خرید رو بزن.چون خیلی سریع هم تموم میشد.ما هم می‌دیدیم اگه موجودی والتش اندازه بود، می‌خریدیم براش و فعالش می‌کردیم روی اکانتش.حالا این وسط یه مشتری ما با موجودی بر فرض 5$ اومده بود یه خرید بزنه و اشتراک بخره.در لحظه‌ای که میاد اشتراک رو بخره، یه تسک دیگه میاد از حساب والت چند سنت خرید رو کم میکنه و اون سرویس هفتگی رو براش فعال میکنه.تقریباً:11 سنتحالا این وسط چه اتفاقی می‌افته؟این دوتا Request یه‌جورایی پشت سر هم اتفاق می‌افتن.و Wallet کاربر توی دیتابیس شده:$4.89ولی خرید اون محصول مورد نظر مشتری بوده:$4.99از اون جالب‌تر اینکه Query ما هم داشته می‌گفته:$5در جایی که اصلاً نمی‌تونسته اگه موجودی کافی نبوده به این قسمت برسه!حالا بریم بررسی کنیم داستان چی بوده.مشکل از SQLAlchemy Session بودیه موضوعی هست توی SQLAlchemy در رابطه با Sessionها.برنامه‌نویس این سرویس بنده‌خدا فکر می‌کرده وقتی داره می‌نویسه:stmt = (&#xA;    select(Wallet, User)&#xA;    .join(User, User.id == Wallet.user_id)&#xA;    .where(Wallet.user_id == user_id)&#xA;)&#xA;&#xA;result = await session.execute(stmt)&#xA;wallet, user = result.one()&#xA;&#xA;&#xA;time.sleep(10)  # PROCESS&#xA;&#xA;stmt = (&#xA;    select(Wallet, User)&#xA;    .join(User, User.id == Wallet.user_id)&#xA;    .where(Wallet.user_id == user_id)&#xA;)&#xA;&#xA;result = await session.execute(stmt)&#xA;wallet, user = result.one()این یعنی SQLAlchemy دوباره داره Query میزنه به دیتابیس و مقدار جدید رو می‌گیره.اما امان از دل غافل!شما وقتی توی یه Session یه Object رو دارین و قبلاً گرفتین، اگه دوباره Query بزنین، SQLAlchemy می‌بینه این Object رو توی Session خودش داره.در نتیجه ممکنه همون Object موجود در Session رو برگردونه، بدون اینکه مقدار Attributeهای اون Object رو از دیتابیس دوباره پر کنه.مثلاً:Database:&#xA;balance = 4.89&#xA;&#xA;Session:&#xA;wallet.balance = 5.00در این حالت شما ممکنه دوباره Query بزنین، اما همچنان این مقدار رو ببینید:wallet.balance&#xA;# 5.00در حالی که مقدار واقعی دیتابیس:4.89استاستفاده از populate_existing=Trueبرای چنین شرایطی می‌تونیم از:.execution_options(populate_existing=True)استفاده کنیم:stmt = (&#xA;    select(Wallet, User)&#xA;    .join(User, User.id == Wallet.user_id)&#xA;    .where(Wallet.user_id == user_id)&#xA;    .execution_options(&#xA;        populate_existing=True&#xA;    )&#xA;)&#xA;&#xA;result = await session.execute(stmt)&#xA;wallet, user = result.one()اینجا به SQLAlchemy می‌گیم نتایج این Query رو حتی اگه Object مربوطه از قبل داخل Session وجود داشته باشه، دوباره روی Object موجود اعمال کن.بنابراین اگر در این فاصله موجودی Wallet تغییر کرده باشه:قبل:&#xA;&#xA;Session:&#xA;$5.00&#xA;&#xA;Database:&#xA;$5.00و یک Request دیگه موجودی رو تغییر بده:Database:&#xA;$4.89Query با:.execution_options(&#xA;    populate_existing=True&#xA;)باعث میشه مقدار Object موجود در Session هم دوباره با مقدار Query پر بشه:Session:&#xA;$4.89&#xA;&#xA;Database:&#xA;$4.89ولی session.refresh(obj) چی؟شاید در لحظه بگین:session.refresh(obj) هم می‌تونستیم استفاده کنیم.که درست هم هست.ولی این دوتا یه فرق اساسی دارن.وقتی میای:await session.refresh(wallet)میگی:عزیز من، برو همین obj مشخص رو دوباره از دیتابیس بخون و آپدیتش کن.یعنی تمرکز روی همون Object مشخصه.ولی وقتی از:.execution_options(&#xA;    populate_existing=True&#xA;)استفاده می‌کنی، داری میگی:نتایج این Query رو حتی اگه Object مربوطه از قبل توی Session وجود داشته باشه، برو بگیر و دوباره روی Object موجود اعمال کن.پس به شکل ساده:session.refresh(obj)&#xA;        ↓&#xA;همین Object مشخص رو دوباره از Database بخوندر مقابل:populate_existing=True&#xA;        ↓&#xA;نتایج این Query رو روی Objectهای موجود در Session هم اعمال کنیک نکته مهمبماند که این پروژه رو ما چندین ماه داشتیم ریفکتور می‌کردیم و این اتفاق به دلیل وحشتناک بودن و مزخرف بودن Source Code افتاده بود.در کل مهمه که توی SQLAlchemy حواستون باشه که دیتا داره از Objectی که توی Session هست خونده میشه یا Query واقعاً داره مقدار مورد نظر رو از سمت Database می‌گیره.مخصوصاً وقتی با شرایطی مثل این‌ها روبه‌رو هستید:چند Request همزمانBackground Taskچند Workerتغییر داده توسط Transactionهای مختلفQueueهاتغییر اطلاعات خارج از Session فعلیاین موارد می‌تونن باعث بشن چیزی که داخل Object می‌بینید با چیزی که واقعاً داخل Database وجود داره متفاوت باشه.در چنین شرایطی باید بدونید SQLAlchemy Session دقیقاً چه رفتاری با Objectهایی که قبلاً Load شدن داره.اگه خوشتون اومده باشه، بعداً میتونیم بیشتر راجع بهش صحبت کنیم.من صفحه های دیگه ایی هم دارم:کانال تلگرامی DjangoUpیوتیوب من: MasoudKheradmandi</description><category>Masoud Kheradmandi</category><author>Masoud Kheradmandi</author><pubDate>Mon, 05 Oct 2026 14:21:19 +0330</pubDate></item><item><title>ایندکس جزئی (Partial Index) چیست؟</title><link>https://virgool.ir/@kheradmandimasoud416/ایندکس-جزئی-partial-index-چیست-xrg0ee6cw142</link><description>ایندکس جزئی یکی از قابلیت‌های پیشرفته در پایگاه‌های داده‌ است که به شما امکان می‌دهد تنها بخشی از رکوردهای جدول را ایندکس کنید، نه تمام آن‌ها(بهتر بگم ینی یک value خاص رو ایندکس میکنیم) این نوع ایندکس با استفاده از یک شرط خاص (مانند یک عبارت WHERE) تعیین می‌شود و فقط رکوردهایی که شرط ذکر شده را دارند اوورده میشود❗️مزایای ایندکس جزئی:- عملکرد بهینه‌تر: ایندکس جزئی حجم کمتری دارد و بنابراین جستجوهای مرتبط با شرط خاص سریع‌تر انجام می‌شوند.- کاهش فضای ذخیره‌سازی: به دلیل این‌که تنها بخشی از داده‌ها ایندکس می‌شوند، فضای کمتری در پایگاه داده مصرف می‌شود.- بهینه برای شرایط خاص: اگر کوئری‌های شما معمولاً شامل یک شرط خاص (مثلاً status = True) باشه ، ایندکس جزئی میتونه خیلی مؤثر باشهبرای مثال شما یک Table Product رو تصور کنید که یک ستون active داره و شما هر دفعه اونایی که True هستن رو نمایش میدین یه نمونه کد در جنگو هم ببینیم&#xA;class YourModel(models.Model):&#xA;    active = models.BooleanField()&#xA;&#xA;    class Meta:&#xA;&#xA;        indexes = [&#xA;&#xA;            models.Index(fields=[&#39;active&#39;], name=&#39;active_true_idx&#39;, condition=models.Q(active=True)),&#xA;&#xA;        ]من امیرمسعود خردمندی هستمکانال تلگرامی من: DjangoUpدر یوتیوب هم من رو به Masoud kheradmandi سرچ کنید</description><category>Masoud Kheradmandi</category><author>Masoud Kheradmandi</author><pubDate>Mon, 05 Oct 2026 03:03:44 +0330</pubDate></item></channel></rss>