كانت أوامرنا سجينة الطرفية (Terminal): كيف حررنا ‘ChatOps’ من جحيم الاستجابة البطيئة؟

بتذكرها زي كأنها مبارح، ليلة خميس شتوية من هداك النوع اللي بتحس فيه البرد واصل للعظم. الساعة كانت حوالي 2 بعد نص الليل، والتلفون رن. لما يكون تلفونك سايلنت طول اليوم، بس رنته بتصحى عليها بنص الليل، بتعرف إنه “ولعت”. كان أحمد، المهندس الجديد اللي معنا بالفريق، صوته برجف: “أبو عمر، الحقني! السيرفر الرئيسي تبع الدفعات واقع، والعملاء بلشوا يشتكوا على تويتر!”.

قلبي نغزني. قمت بسرعة، شغلت اللابتوب، استنيت الـ VPN يشبك، فتحت الطرفية (Terminal)، وعملت SSH على السيرفر… كل هاد وأنا بسمع صوت نقر أحمد على الكيبورد من الطرف التاني وهو بحاول يعمل نفس الشي. أخذت منا القصة حوالي 15 دقيقة بس لنوصل لمرحلة نقدر فيها نكتب أول أمر. 15 دقيقة في عالم المدفوعات تعني خسائر بالآلاف. بعد ما حلينا المشكلة (اللي كانت مجرد خدمة محتاجة إعادة تشغيل)، قعدت مع فنجان الشاي وأنا بفكر: “مش معقول نضل هيك! أوامرنا التشغيلية محبوسة، ومفتاح السجن مع كم واحد بس. لازم نلاقي حل.”.

من هداك اليوم، بدأت رحلتنا لتحرير أوامرنا، والحل كان اسمه: ChatOps.

ما هو سجن “الطرفية” الذي نتحدث عنه؟

قبل ما نحكي عن الحل، خلينا نفهم أبعاد المشكلة اللي كنا (والكثير من الفرق لا تزال) عايشين فيها. المشكلة مش في الطرفية نفسها، فهي أداة قوية وممتازة. المشكلة في كيفية الوصول إليها وتشغيل الأوامر الحاسمة:

  • حاجز الوصول (Access Barrier): لتشغيل أمر على خادم إنتاجي، تحتاج عادةً إلى: VPN، ثم اتصال SSH، وأحيانًا المرور عبر خادم وسيط (Bastion Host)، وكل هذا يتطلب أذونات وملفات مفاتيح خاصة.
  • عنق الزجاجة البشري (Human Bottleneck): عادةً ما تكون هذه الصلاحيات محصورة في عدد قليل من الأشخاص (فريق DevOps، كبار المطورين). إذا كان الشخص المناسب نائماً أو في إجازة، تتعطل العملية بأكملها.
  • انعدام الشفافية (Lack of Transparency): عندما يقوم مهندس بحل مشكلة عبر SSH، ما الذي يحدث بالضبط؟ ما هي الأوامر التي تم تنفيذها؟ ما كانت نتائجها؟ كل هذا يحدث في “صندوق أسود”. لا أحد يرى أو يتعلم إلا إذا تم توثيق كل خطوة يدويًا، وهو أمر نادر الحدوث في خضم الأزمات.

  • بطء الاستجابة (Slow Response): كما رأيتم في قصتي، الوقت من اكتشاف المشكلة إلى تنفيذ أول أمر لإصلاحها يمكن أن يكون طويلاً بشكل كارثي.

هذا هو السجن الذي كانت أوامرنا التشغيلية حبيسة فيه. سجن منيع، بطيء، وغير شفاف.

ChatOps: الثورة التي حررت أوامرنا

ببساطة شديدة، الـ ChatOps هو ممارسة تنفيذ المهام التشغيلية من خلال واجهة محادثة (Chat Interface). بدلًا من فتح الطرفية، أنت تكتب أمرًا للبوت (Bot) الخاص بفريقك على Slack، أو Microsoft Teams، أو أي منصة محادثة أخرى.

الفكرة الجوهرية للـ ChatOps هي: “أحضر أدواتك إلى حيث تدور المحادثة، لا تأخذ المحادثة إلى أدواتك.”

عندما تحدث مشكلة، أين يتجمع الفريق؟ في قناة Slack. إذًا، لماذا لا نجعل الأدوات متاحة في نفس المكان؟

كيف يعمل هذا السحر؟

الآلية ليست سحرًا، بل هي هندسة برمجيات ذكية. تتكون المنظومة عادةً من الأجزاء التالية:

  1. منصة المحادثة (Chat Platform): مثل Slack, MS Teams, Discord. هذا هو المكان الذي يتفاعل فيه المستخدمون.
  2. البوت (The Bot): هذا هو قلب العملية. هو برنامج يستمع للأوامر في قناة المحادثة، يفهمها، ويقوم بالرد.
  3. الواجهة الخلفية (Backend Service): عندما يستقبل البوت أمرًا (مثل `/ops deploy app-X to staging`)، فإنه لا ينفذه مباشرةً في العادة. بل يرسله إلى خدمة خلفية آمنة.
  4. منفذ الأوامر (Execution Layer): الخدمة الخلفية هي التي لديها الصلاحيات الفعلية لتنفيذ المهمة. قد تقوم باستدعاء Ansible playbook، أو تشغيل وظيفة في Jenkins، أو تنفيذ أوامر `kubectl` على Kubernetes cluster، أو حتى مجرد تشغيل سكربت Shell.

الجمال في هذا التصميم هو الفصل بين الواجهة (البوت) والمنطق الحقيقي (الخدمة الخلفية)، مما يضيف طبقة مهمة من الأمان والتحكم.

لنطبق عمليًا: بناء بوت ChatOps بسيط

الحكي سهل، خلينا نشوف مثال عملي. لنفترض أننا نريد بناء بوت بسيط على Slack باستخدام Python ومكتبة `slack_bolt` ليقوم بمهمتين:

  1. التحقق من حالة خدمة معينة.
  2. إعادة تشغيل خدمة (بعد التأكيد).

h3: الإعدادات الأولية

أولاً، ستحتاج إلى إنشاء تطبيق Slack والحصول على `Bot Token` و `Signing Secret`. هذه العملية موثقة جيدًا على موقع Slack API.

بعد ذلك، قم بتثبيت المكتبات اللازمة:

pip install slack_bolt python-dotenv

h3: كتابة كود البوت

هذا مثال مبسط جدًا لكود البوت. في العالم الحقيقي، سيكون المنطق أكثر تعقيدًا وسيفصل في خدمات مختلفة.


import os
from dotenv import load_dotenv
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

# تحميل متغيرات البيئة (الأمان أولاً!)
load_dotenv()
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN")
SLACK_APP_TOKEN = os.environ.get("SLACK_APP_TOKEN")

# تهيئة التطبيق
app = App(token=SLACK_BOT_TOKEN)

# --- منطق وهمي لتنفيذ الأوامر ---
# في الواقع، هذا الجزء سيستدعي Ansible, Kubernetes, etc.
def check_service_status(service_name):
    print(f"Checking status for: {service_name}")
    # هنا تضع منطق فحص الخدمة الحقيقي
    return f"✅ الخدمة `{service_name}` تعمل بشكل سليم."

def restart_service_action(service_name):
    print(f"RESTARTING service: {service_name}")
    # هنا تضع منطق إعادة التشغيل الحقيقي
    return f"🚀 تم إرسال طلب إعادة تشغيل للخدمة `{service_name}`."
# -----------------------------------


# الاستماع لأمر /status
@app.command("/status")
def handle_status_command(ack, body, client, logger):
    # إقرار باستلام الأمر فورًا لتجنب الـ timeout
    ack()
    
    service_name = body.get('text', 'unknown_service')
    logger.info(f"Received /status command for service: {service_name}")
    
    # تنفيذ المنطق والحصول على النتيجة
    result_message = check_service_status(service_name)
    
    # إرسال الرد في القناة
    client.chat_postMessage(channel=body['channel_id'], text=result_message)


# الاستماع لأمر /restart
@app.command("/restart")
def handle_restart_command(ack, body, client, logger):
    ack()
    
    service_name = body.get('text', '')
    if not service_name:
        client.chat_postMessage(channel=body['channel_id'], text="الرجاء تحديد اسم الخدمة. مثال: `/restart payment-service`")
        return

    # إرسال رسالة تأكيد تفاعلية
    client.chat_postMessage(
        channel=body['channel_id'],
        text=f"هل أنت متأكد من أنك تريد إعادة تشغيل الخدمة `{service_name}`؟",
        blocks=[
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"🚨 *تحذير:* أنت على وشك إعادة تشغيل الخدمة `{service_name}`. هل أنت متأكد؟"
                }
            },
            {
                "type": "actions",
                "block_id": "restart_confirmation_block",
                "elements": [
                    {
                        "type": "button",
                        "text": {"type": "plain_text", "text": "نعم، أعد التشغيل"},
                        "style": "danger",
                        "value": service_name,
                        "action_id": "confirm_restart"
                    },
                    {
                        "type": "button",
                        "text": {"type": "plain_text", "text": "لا، إلغاء"},
                        "action_id": "cancel_restart"
                    }
                ]
            }
        ]
    )

# الاستماع لزر التأكيد
@app.action("confirm_restart")
def handle_confirm_restart(ack, body, client, logger):
    ack()
    
    service_name = body['actions'][0]['value']
    user = body['user']['id']
    
    # تحديث الرسالة الأصلية لإظهار من قام بالفعل
    original_message_ts = body['message']['ts']
    channel_id = body['channel']['id']
    
    client.chat_update(
        channel=channel_id,
        ts=original_message_ts,
        text=f"طلب إعادة تشغيل الخدمة `{service_name}` تم تأكيده بواسطة .",
        blocks=[] # إزالة الأزرار
    )

    # تنفيذ الإجراء الفعلي
    result = restart_service_action(service_name)
    
    # إعلام القناة بالنتيجة
    client.chat_postMessage(channel=channel_id, text=result)


# الاستماع لزر الإلغاء
@app.action("cancel_restart")
def handle_cancel_restart(ack, body, client):
    ack()
    original_message_ts = body['message']['ts']
    channel_id = body['channel']['id']
    user = body['user']['id']
    
    client.chat_update(
        channel=channel_id,
        ts=original_message_ts,
        text=f"عملية إعادة التشغيل تم إلغاؤها بواسطة .",
        blocks=[]
    )


# تشغيل التطبيق
if __name__ == "__main__":
    handler = SocketModeHandler(app, SLACK_APP_TOKEN)
    handler.start()

هذا المثال يوضح مبادئ أساسية: استقبال الأوامر، طلب التأكيد للأفعال الخطيرة، وتسجيل ما يحدث. تخيل الآن توسيع هذا المبدأ ليشمل نشر التطبيقات، استرجاع Logs، فحص حالة قواعد البيانات، أو أي مهمة روتينية أخرى.

نصائح أبو عمر الذهبية لتطبيق ChatOps ناجح

بعد سنوات من بناء وتطوير هذه الأنظمة، تعلمت بعض الدروس بالطريقة الصعبة. خذوها مني نصيحة “من الآخر”:

  1. ابدأ صغيرًا (Start Small): لا تحاول أتمتة عملية إطلاق صاروخ في أول يوم. ابدأ بمهمة بسيطة، متكررة، ومنخفضة المخاطر. مثل أمر `/status` الذي عرضناه. النجاحات الصغيرة تبني الثقة وتبرر الاستثمار في المشروع. “ما تبدأ كبير وتغرق”.
  2. الأمان أولًا، وأخيرًا، ودائمًا: هذه أهم نصيحة. لا تضع أي مفاتيح أو كلمات سر في الكود. استخدم متغيرات البيئة (Environment Variables) ومدير الأسرار (Secrets Manager). طبق نظام صلاحيات (RBAC – Role-Based Access Control) صارم. ليس كل شخص في القناة يجب أن يكون قادرًا على تشغيل أمر `/deploy-to-production`. يمكنك ربط صلاحيات البوت بصلاحيات المستخدمين في مجموعات Active Directory أو Okta.
  3. صمّم من أجل الشفافية: يجب أن يعلن البوت بوضوح كل ما يفعله. “المستخدم X طلب إعادة تشغيل الخدمة Y… جاري التنفيذ… تم التنفيذ بنجاح.” هذه الشفافية تبني الثقة وتخلق سجلًا تاريخيًا (Audit Trail) لا يقدر بثمن.
  4. اطلب التأكيد للأفعال المدمرة: أي أمر يغير حالة النظام (نشر، إعادة تشغيل، حذف) يجب أن يطلب تأكيدًا واضحًا، ويفضل أن يكون بزر كما في المثال. هذا يمنع الأخطاء الكارثية الناتجة عن خطأ في الكتابة.
  5. اجعل البوت مفيدًا وليس مزعجًا: لا تجعل البوت يغرق القناة بالرسائل غير المهمة. أعطه القدرة على الرد في “ثريد” (Thread) للحفاظ على نظافة القناة الرئيسية.

الخلاصة: ChatOps ليست أداة، بل ثقافة 🚀

رحلتنا من ليلة الكابوس تلك إلى عالم ChatOps لم تكن مجرد تغيير تقني. كانت تغييرًا في الثقافة. لقد حررنا أوامرنا من سجن الطرفية، ولكننا في المقابل كسبنا ما هو أهم بكثير:

  • سرعة استجابة فورية للأزمات.
  • شفافية كاملة يراها كل الفريق.
  • تعاون حقيقي بين المطورين والعمليات (DevOps).
  • تمكين لأعضاء الفريق لتنفيذ مهام كانوا يخشونها سابقًا.

لم يعد أحمد، المهندس الجديد، يخشى مناوبات الليل. الآن، يمكنه تشغيل أمر تشخيصي آمن من هاتفه المحمول عبر Slack، وإذا لزم الأمر، يمكنه تصعيد المشكلة مع توفير كل السياق اللازم للفريق الأقدم. لقد أصبح الجميع أكثر قوة، وأصبحت أنظمتنا أكثر استقرارًا.

نصيحتي الأخيرة لك: لا تنظر إلى ChatOps على أنها مجرد “بوت” ظريف. انظر إليها على أنها فرصة لإعادة التفكير في كيفية عمل فريقك، وكيفية بناء الثقة من خلال الأتمتة والشفافية. يلا يا شباب، ابدأوا اليوم وحرروا أوامركم!

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

اختبارات الاداء والجودة

من وهم الـ 100% إلى جودة حقيقية: كيف أنقذتنا اختبارات الطفرات (Mutation Testing) من جحيم المقاييس الخادعة؟

كنا نحتفل بنسبة تغطية اختبارات 100%، لكن الكود كان مليئًا بالعلل الخفية. هذه قصتي كـ"أبو عمر" وكيف كشفت "اختبارات الطفرات" (Mutation Testing) ضعف اختباراتنا وقادتنا...

27 أبريل، 2026 قراءة المزيد
ذكاء اصطناعي

كنا نبحث عن الإبرة في كومة قش: كيف أنقذتنا ‘قواعد بيانات المتجهات’ من جحيم البحث الدلالي البدائي؟

أشارككم قصة حقيقية من تجربتي كمطور، وكيف انتقلنا من البحث البدائي المعتمد على الكلمات المفتاحية إلى البحث الدلالي الذكي. اكتشفوا معنا عالم قواعد بيانات المتجهات...

27 أبريل، 2026 قراءة المزيد
خوارزميات

كنا نحرق الذاكرة لحساب المستخدمين الفريدين: كيف أنقذتنا خوارزمية HyperLogLog من جحيم استهلاك الموارد؟

أشارككم قصة حقيقية من الميدان، عندما كادت خوادمنا أن تنهار بسبب عد المستخدمين بالطريقة الساذجة. اكتشفوا معنا خوارزمية HyperLogLog السحرية التي وفرت 99% من الذاكرة...

27 أبريل، 2026 قراءة المزيد
تسويق رقمي

كنا نلاحق الكلمات الطويلة يدوياً: كيف أنقذنا التحسين البرمجي لمحركات البحث (Programmatic SEO) من جحيم الفرص الضائعة؟

أتذكر جيداً أيام الملاحقة اليدوية للكلمات المفتاحية الطويلة، جهدٌ ضائع ووقتٌ مهدر. في هذه المقالة، أشارككم قصة كيف غيّر "التحسين البرمجي لمحركات البحث" (Programmatic SEO)...

26 أبريل، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

كانت واجهتنا بلا روح: كيف أنقذتنا ‘التفاعلات الدقيقة’ من جحيم التجربة الصامتة؟

أشارككم قصة حقيقية من قلب مشاريع البرمجة، كيف كان تطبيقنا يعمل بكفاءة لكنه "ميت سريرياً". اكتشفوا معنا عالم "التفاعلات الدقيقة" (Microinteractions)، تلك اللمسات السحرية التي...

26 أبريل، 2026 قراءة المزيد
البودكاست