مثال لتطبيق قائم على الأحداث يعتمد على خطافات الويب في تخزين الكائنات S3 Mail.ru Cloud Solutions

مثال لتطبيق قائم على الأحداث يعتمد على خطافات الويب في تخزين الكائنات S3 Mail.ru Cloud Solutions
آلة القهوة روب غولدبرغ

تعمل البنية المبنية على الأحداث على زيادة كفاءة تكلفة الموارد المستخدمة لأنها تستخدم فقط في الوقت الذي تكون فيه هناك حاجة إليها. هناك العديد من الخيارات حول كيفية تنفيذ ذلك وعدم إنشاء كيانات سحابية إضافية كتطبيقات عاملة. واليوم لن أتحدث عن FaaS، بل عن خطافات الويب. سأعرض مثالاً تعليميًا للتعامل مع الأحداث باستخدام خطافات الويب لتخزين الكائنات.

بضع كلمات حول تخزين الكائنات وخطافات الويب. يسمح لك تخزين الكائنات بتخزين أي بيانات في السحابة في شكل كائنات، ويمكن الوصول إليها عبر S3 أو واجهة برمجة تطبيقات أخرى (اعتمادًا على التنفيذ) عبر HTTP/HTTPS. تعد خطافات الويب بشكل عام عمليات رد اتصال HTTP مخصصة. وعادةً ما يتم تشغيلها بواسطة حدث ما، مثل دفع التعليمات البرمجية إلى أحد المستودعات أو نشر تعليق على مدونة. عند وقوع حدث ما، يرسل الموقع الأصلي طلب HTTP إلى عنوان URL المحدد لخطاف الويب. ونتيجة لذلك، يمكنك جعل الأحداث الموجودة على أحد المواقع تؤدي إلى تشغيل إجراءات على موقع آخر (ويكي). في الحالة التي يكون فيها الموقع المصدر مخزنًا للكائنات، تعمل الأحداث بمثابة تغييرات على محتوياته.

أمثلة على الحالات البسيطة التي يمكن فيها استخدام هذه الأتمتة:

  1. إنشاء نسخ من جميع الكائنات الموجودة في وحدة تخزين سحابية أخرى. يجب إنشاء النسخ بسرعة عند إضافة الملفات أو تغييرها.
  2. الإنشاء التلقائي لسلسلة من الصور المصغرة للملفات الرسومية، وإضافة العلامات المائية للصور الفوتوغرافية، وتعديلات الصور الأخرى.
  3. إشعار بوصول مستندات جديدة (على سبيل المثال، تقوم خدمة المحاسبة الموزعة بتحميل التقارير إلى السحابة، وتتلقى المراقبة المالية إشعارات حول التقارير الجديدة، وتقوم بفحصها وتحليلها).
  4. تتضمن الحالات الأكثر تعقيدًا بعض الشيء، على سبيل المثال، إنشاء طلب إلى Kubernetes، الذي ينشئ حجرة تحتوي على الحاويات الضرورية، ويمرر معلمات المهمة إليها، وبعد المعالجة ينهار الحاوية.

على سبيل المثال، سننشئ متغيرًا للمهمة 1، عندما تتم مزامنة التغييرات في حاوية تخزين كائنات Mail.ru Cloud Solutions (MCS) في تخزين كائنات AWS باستخدام خطافات الويب. في حالة التحميل الحقيقي، يجب توفير العمل غير المتزامن عن طريق تسجيل خطافات الويب في قائمة الانتظار، ولكن بالنسبة لمهمة التدريب، فسنقوم بالتنفيذ بدون ذلك.

مخطط العمل

تم وصف بروتوكول التفاعل بالتفصيل في دليل لخطافات الويب S3 على MCS. يحتوي مخطط العمل على العناصر التالية:

  • خدمة النشر، الموجود على جانب تخزين S3 وينشر طلبات HTTP عند تشغيل webnhook.
  • خادم استقبال Webhook، الذي يستمع للطلبات الواردة من خدمة النشر HTTP وينفذ الإجراءات المناسبة. يمكن كتابة الخادم بأي لغة؛ في مثالنا، سنكتب الخادم بلغة Go.

إحدى الميزات الخاصة لتنفيذ خطافات الويب في S3 API هي تسجيل خادم استلام خطاف الويب على خدمة النشر. على وجه الخصوص، يجب أن يؤكد خادم استقبال webhook الاشتراك في الرسائل من خدمة النشر (في تطبيقات webhook الأخرى، عادةً لا يكون تأكيد الاشتراك مطلوبًا).

وبناء على ذلك، يجب أن يدعم خادم استقبال webhook عمليتين رئيسيتين:

  • الرد على طلب خدمة النشر لتأكيد التسجيل،
  • معالجة الأحداث الواردة.

تثبيت خادم استقبال webhook

لتشغيل خادم استقبال webhook، تحتاج إلى خادم Linux. في هذه المقالة، على سبيل المثال، نستخدم مثيلًا افتراضيًا نقوم بنشره على MCS.

لنقم بتثبيت البرنامج الضروري وتشغيل خادم استقبال webhook.

ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install git
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  bc dns-root-data dnsmasq-base ebtables landscape-common liblxc-common 
liblxc1 libuv1 lxcfs lxd lxd-client python3-attr python3-automat 
python3-click python3-constantly python3-hyperlink
  python3-incremental python3-pam python3-pyasn1-modules 
python3-service-identity python3-twisted python3-twisted-bin 
python3-zope.interface uidmap xdelta3
Use 'sudo apt autoremove' to remove them.
Suggested packages:
  git-daemon-run | git-daemon-sysvinit git-doc git-el git-email git-gui 
gitk gitweb git-cvs git-mediawiki git-svn
The following NEW packages will be installed:
  git
0 upgraded, 1 newly installed, 0 to remove and 46 not upgraded.
Need to get 3915 kB of archives.
After this operation, 32.3 MB of additional disk space will be used.
Get:1 http://MS1.clouds.archive.ubuntu.com/ubuntu bionic-updates/main 
amd64 git amd64 1:2.17.1-1ubuntu0.7 [3915 kB]
Fetched 3915 kB in 1s (5639 kB/s)
Selecting previously unselected package git.
(Reading database ... 53932 files and directories currently installed.)
Preparing to unpack .../git_1%3a2.17.1-1ubuntu0.7_amd64.deb ...
Unpacking git (1:2.17.1-1ubuntu0.7) ...
Setting up git (1:2.17.1-1ubuntu0.7) ...

استنساخ المجلد باستخدام خادم استقبال webhook:

ubuntu@ubuntu-basic-1-2-10gb:~$ git clone
https://github.com/RomanenkoDenys/s3-webhook.git
Cloning into 's3-webhook'...
remote: Enumerating objects: 48, done.
remote: Counting objects: 100% (48/48), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 114 (delta 20), reused 45 (delta 18), pack-reused 66
Receiving objects: 100% (114/114), 23.77 MiB | 20.25 MiB/s, done.
Resolving deltas: 100% (49/49), done.

لنبدأ الخادم:

ubuntu@ubuntu-basic-1-2-10gb:~$ cd s3-webhook/
ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80

الاشتراك في خدمة النشر

يمكنك تسجيل خادم استقبال webhook الخاص بك عبر واجهة برمجة التطبيقات أو واجهة الويب. للتبسيط، سنقوم بالتسجيل عبر واجهة الويب:

  1. دعنا نذهب إلى قسم الدلاء في غرفة التحكم.
  2. انتقل إلى المجموعة التي سنقوم بتكوين خطافات الويب لها وانقر على الترس:

مثال لتطبيق قائم على الأحداث يعتمد على خطافات الويب في تخزين الكائنات S3 Mail.ru Cloud Solutions

انتقل إلى علامة التبويب Webhooks وانقر فوق "إضافة":

مثال لتطبيق قائم على الأحداث يعتمد على خطافات الويب في تخزين الكائنات S3 Mail.ru Cloud Solutions
املأ الحقول:

مثال لتطبيق قائم على الأحداث يعتمد على خطافات الويب في تخزين الكائنات S3 Mail.ru Cloud Solutions

المعرف - اسم خطاف الويب.

الحدث - الأحداث التي سيتم نقلها. لقد قمنا بتعيين نقل جميع الأحداث التي تحدث عند العمل مع الملفات (الإضافة والحذف).

URL — خطاف الويب لتلقي عنوان الخادم.

بادئة/لاحقة عامل التصفية عبارة عن مرشح يسمح لك بإنشاء خطافات ويب فقط للكائنات التي تتطابق أسماؤها مع قواعد معينة. على سبيل المثال، لكي يقوم خطاف الويب بتشغيل الملفات ذات الامتداد .png فقط، في لاحقة التصفية عليك أن تكتب "png".

حاليًا، يتم دعم المنفذين 80 و443 فقط للوصول إلى خادم استلام الخطاف عبر الويب.

دعونا انقر إضافة هوك وسنرى ما يلي:

مثال لتطبيق قائم على الأحداث يعتمد على خطافات الويب في تخزين الكائنات S3 Mail.ru Cloud Solutions
تمت إضافة الخطاف.

يُظهر خادم استلام الخطاف في سجلاته تقدم عملية تسجيل الخطاف:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80
2020/06/15 12:01:14 [POST] incoming HTTP request from 
95.163.216.92:42530
2020/06/15 12:01:14 Got timestamp: 2020-06-15T15:01:13+03:00 TopicArn: 
mcs5259999770|myfiles-ash|s3:ObjectCreated:*,s3:ObjectRemoved:* Token: 
E2itMqAMUVVZc51pUhFWSp13DoxezvRxkUh5P7LEuk1dEe9y URL: 
http://89.208.199.220/webhook
2020/06/15 12:01:14 Generate responce signature: 
3754ce36636f80dfd606c5254d64ecb2fd8d555c27962b70b4f759f32c76b66d

اكتمل التسجيل. في القسم التالي، سننظر بمزيد من التفصيل في خوارزمية تشغيل خادم استقبال الويب هوك.

وصف خادم استقبال webhook

في مثالنا، الخادم مكتوب باللغة Go. دعونا نلقي نظرة على المبادئ الأساسية لعملها.

package main

// Generate hmac_sha256_hex
func HmacSha256hex(message string, secret string) string {
}

// Generate hmac_sha256
func HmacSha256(message string, secret string) string {
}

// Send subscription confirmation
func SubscriptionConfirmation(w http.ResponseWriter, req *http.Request, body []byte) {
}

// Send subscription confirmation
func GotRecords(w http.ResponseWriter, req *http.Request, body []byte) {
}

// Liveness probe
func Ping(w http.ResponseWriter, req *http.Request) {
    // log request
    log.Printf("[%s] incoming HTTP Ping request from %sn", req.Method, req.RemoteAddr)
    fmt.Fprintf(w, "Pongn")
}

//Webhook
func Webhook(w http.ResponseWriter, req *http.Request) {
}

func main() {

    // get command line args
    bindPort := flag.Int("port", 80, "number between 1-65535")
    bindAddr := flag.String("address", "", "ip address in dot format")
    flag.StringVar(&actionScript, "script", "", "external script to execute")
    flag.Parse()

    http.HandleFunc("/ping", Ping)
    http.HandleFunc("/webhook", Webhook)

log.Fatal(http.ListenAndServe(*bindAddr+":"+strconv.Itoa(*bindPort), nil))
}

ضع في اعتبارك الوظائف الرئيسية:

  • Ping() - مسار يستجيب عبر URL/ping، وهو أبسط تنفيذ لمسبار الحيوية.
  • Webhook() - المسار الرئيسي، معالج URL/webhook:
    • تأكيد التسجيل في خدمة النشر (انتقل إلى وظيفة تأكيد الاشتراك)،
    • يعالج خطافات الويب الواردة (وظيفة Gorecords).
  • الوظيفتان HmacSha256 وHmacSha256hex عبارة عن تطبيقات لخوارزميات التشفير HMAC-SHA256 وHMAC-SHA256 مع إخراج كسلسلة من الأرقام السداسية العشرية لحساب التوقيع.
  • main هي الوظيفة الرئيسية، وتعالج معلمات سطر الأوامر وتسجل معالجات URL.

معلمات سطر الأوامر المقبولة من قبل الخادم:

  • -port هو المنفذ الذي سيستمع إليه الخادم.
  • -address - عنوان IP الذي سيستمع إليه الخادم.
  • -script هو برنامج خارجي يتم استدعاؤه لكل خطاف وارد.

دعونا نلقي نظرة فاحصة على بعض الوظائف:

//Webhook
func Webhook(w http.ResponseWriter, req *http.Request) {

    // Read body
    body, err := ioutil.ReadAll(req.Body)
    defer req.Body.Close()
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    // log request
    log.Printf("[%s] incoming HTTP request from %sn", req.Method, req.RemoteAddr)
    // check if we got subscription confirmation request
    if strings.Contains(string(body), 
""Type":"SubscriptionConfirmation"") {
        SubscriptionConfirmation(w, req, body)
    } else {
        GotRecords(w, req, body)
    }

}

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

POST http://test.com HTTP/1.1
x-amz-sns-messages-type: SubscriptionConfirmation
content-type: application/json

{
    "Timestamp":"2019-12-26T19:29:12+03:00",
    "Type":"SubscriptionConfirmation",
    "Message":"You have chosen to subscribe to the topic $topic. To confirm the subscription you need to response with calculated signature",
    "TopicArn":"mcs2883541269|bucketA|s3:ObjectCreated:Put",
    "SignatureVersion":1,
    "Token":«RPE5UuG94rGgBH6kHXN9FUPugFxj1hs2aUQc99btJp3E49tA»
}

هذا الاستفسار يحتاج إلى إجابة:

content-type: application/json

{"signature":«ea3fce4bb15c6de4fec365d36bcebbc34ccddf54616d5ca12e1972f82b6d37af»}

حيث يتم حساب التوقيع على النحو التالي:

signature = hmac_sha256(url, hmac_sha256(TopicArn, 
hmac_sha256(Timestamp, Token)))

في حالة وصول خطاف ويب، تبدو بنية طلب النشر كما يلي:

POST <url> HTTP/1.1
x-amz-sns-messages-type: SubscriptionConfirmation

{ "Records":
    [
        {
            "s3": {
                "object": {
                    "eTag":"aed563ecafb4bcc5654c597a421547b2",
                    "sequencer":1577453615,
                    "key":"some-file-to-bucket",
                    "size":100
                },
            "configurationId":"1",
            "bucket": {
                "name": "bucketA",
                "ownerIdentity": {
                    "principalId":"mcs2883541269"}
                },
                "s3SchemaVersion":"1.0"
            },
            "eventVersion":"1.0",
            "requestParameters":{
                "sourceIPAddress":"185.6.245.156"
            },
            "userIdentity": {
                "principalId":"2407013e-cbc1-415f-9102-16fb9bd6946b"
            },
            "eventName":"s3:ObjectCreated:Put",
            "awsRegion":"ru-msk",
            "eventSource":"aws:s3",
            "responseElements": {
                "x-amz-request-id":"VGJR5rtJ"
            }
        }
    ]
}

وبناء على ذلك، اعتمادا على الطلب، تحتاج إلى فهم كيفية معالجة البيانات. لقد اخترت الإدخال كمؤشر "Type":"SubscriptionConfirmation"، نظرًا لأنه موجود في طلب تأكيد الاشتراك وغير موجود في خطاف الويب. بناءً على وجود/غياب هذا الإدخال في طلب POST، ينتقل تنفيذ البرنامج الإضافي إما إلى الوظيفة SubscriptionConfirmation، أو في الدالة GotRecords.

لن نتناول وظيفة تأكيد الاشتراك بالتفصيل، بل يتم تنفيذها وفقًا للمبادئ المنصوص عليها في توثيق. يمكنك عرض الكود المصدري لهذه الوظيفة على مستودعات بوابة المشروع.

تقوم وظيفة GotRecords بتوزيع طلب وارد ولكل كائن سجل تستدعي برنامجًا نصيًا خارجيًا (تم تمرير اسمه في المعلمة -script) مع المعلمات:

  • اسم دلو
  • مفتاح الكائن
  • عمل:
    • نسخ - إذا كان في الطلب الأصلي EventName = ObjectCreated | ضع كائن | PutObjectCopy
    • حذف - إذا كان في الطلب الأصلي EventName = ObjectRemoved | حذف كائن

وبالتالي، إذا وصل خطاف مع طلب نشر، كما هو موضح فوقوالمعلمة -script=script.sh ثم سيتم استدعاء البرنامج النصي على النحو التالي:

script.sh  bucketA some-file-to-bucket copy

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

مثال على العمل

لنقم بمزامنة الملفات من المجموعة الرئيسية في MCS إلى مجموعة النسخ الاحتياطي في AWS. يُطلق على المجموعة الرئيسية اسم myfiles-ash، بينما يُطلق على المجموعة الاحتياطية اسم myfiles-backup (يقع تكوين المجموعة في AWS خارج نطاق هذه المقالة). وعليه، عند وضع ملف في المجموعة الرئيسية، يجب أن تظهر نسخته في المجموعة الاحتياطية، وعندما يتم حذفه من المجموعة الرئيسية، يجب حذفه في المجموعة الاحتياطية.

سنعمل مع الدلاء باستخدام الأداة المساعدة awscli، المتوافقة مع كل من التخزين السحابي MCS والتخزين السحابي AWS.

ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install awscli
Reading package lists... Done
Building dependency tree
Reading state information... Done
After this operation, 34.4 MB of additional disk space will be used.
Unpacking awscli (1.14.44-1ubuntu1) ...
Setting up awscli (1.14.44-1ubuntu1) ...

فلنقم بتكوين الوصول إلى S3 MCS API:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile mcs
AWS Access Key ID [None]: hdywEPtuuJTExxxxxxxxxxxxxx
AWS Secret Access Key [None]: hDz3SgxKwXoxxxxxxxxxxxxxxxxxx
Default region name [None]:
Default output format [None]:

فلنقم بتكوين الوصول إلى AWS S3 API:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile aws
AWS Access Key ID [None]: AKIAJXXXXXXXXXXXX
AWS Secret Access Key [None]: dfuerphOLQwu0CreP5Z8l5fuXXXXXXXXXXXXXXXX
Default region name [None]:
Default output format [None]:

دعونا نتحقق من الوصول:

إلى AWS:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile aws
2020-07-06 08:44:11 myfiles-backup

بالنسبة لـ MCS، عند تشغيل الأمر، تحتاج إلى إضافة —endpoint-url:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile mcs --endpoint-url 
https://hb.bizmrg.com
2020-02-04 06:38:05 databasebackups-0cdaaa6402d4424e9676c75a720afa85
2020-05-27 10:08:33 myfiles-ash

تم الوصول إليها.

لنكتب الآن برنامجًا نصيًا لمعالجة الخطاف الوارد، ولنسميه s3_backup_mcs_aws.sh

#!/bin/bash
# Require aws cli
# if file added — copy it to backup bucket
# if file removed — remove it from backup bucket
# Variables
ENDPOINT_MCS="https://hb.bizmrg.com"
AWSCLI_MCS=`which aws`" --endpoint-url ${ENDPOINT_MCS} --profile mcs s3"
AWSCLI_AWS=`which aws`" --profile aws s3"
BACKUP_BUCKET="myfiles-backup"

SOURCE_BUCKET=""
SOURCE_FILE=""
ACTION=""

SOURCE="s3://${SOURCE_BUCKET}/${SOURCE_FILE}"
TARGET="s3://${BACKUP_BUCKET}/${SOURCE_FILE}"
TEMP="/tmp/${SOURCE_BUCKET}/${SOURCE_FILE}"

case ${ACTION} in
    "copy")
    ${AWSCLI_MCS} cp "${SOURCE}" "${TEMP}"
    ${AWSCLI_AWS} cp "${TEMP}" "${TARGET}"
    rm ${TEMP}
    ;;

    "delete")
    ${AWSCLI_AWS} rm ${TARGET}
    ;;

    *)
    echo "Usage: 
#!/bin/bash
# Require aws cli
# if file added — copy it to backup bucket
# if file removed — remove it from backup bucket
# Variables
ENDPOINT_MCS="https://hb.bizmrg.com"
AWSCLI_MCS=`which aws`" --endpoint-url ${ENDPOINT_MCS} --profile mcs s3"
AWSCLI_AWS=`which aws`" --profile aws s3"
BACKUP_BUCKET="myfiles-backup"
SOURCE_BUCKET="${1}"
SOURCE_FILE="${2}"
ACTION="${3}"
SOURCE="s3://${SOURCE_BUCKET}/${SOURCE_FILE}"
TARGET="s3://${BACKUP_BUCKET}/${SOURCE_FILE}"
TEMP="/tmp/${SOURCE_BUCKET}/${SOURCE_FILE}"
case ${ACTION} in
"copy")
${AWSCLI_MCS} cp "${SOURCE}" "${TEMP}"
${AWSCLI_AWS} cp "${TEMP}" "${TARGET}"
rm ${TEMP}
;;
"delete")
${AWSCLI_AWS} rm ${TARGET}
;;
*)
echo "Usage: ${0} sourcebucket sourcefile copy/delete"
exit 1
;;
esac
sourcebucket sourcefile copy/delete" exit 1 ;; esac

لنبدأ الخادم:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80 -
script scripts/s3_backup_mcs_aws.sh

دعونا نرى كيف يعمل. خلال واجهة ويب MCS أضف ملف test.txt إلى مجموعة myfiles-ash. تُظهر سجلات وحدة التحكم أنه تم تقديم طلب إلى خادم webhook:

2020/07/06 09:43:08 [POST] incoming HTTP request from 
95.163.216.92:56612
download: s3://myfiles-ash/test.txt to ../../../tmp/myfiles-ash/test.txt
upload: ../../../tmp/myfiles-ash/test.txt to 
s3://myfiles-backup/test.txt

دعونا نتحقق من محتويات مجموعة النسخ الاحتياطي لملفاتي في AWS:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls 
myfiles-backup
2020-07-06 09:43:10       1104 test.txt

الآن، من خلال واجهة الويب، سنقوم بحذف الملف من حاوية myfiles-ash.

سجلات الخادم:

2020/07/06 09:44:46 [POST] incoming HTTP request from 
95.163.216.92:58224
delete: s3://myfiles-backup/test.txt

محتويات الدلو:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls 
myfiles-backup
ubuntu@ubuntu-basic-1-2-10gb:~$

تم حذف الملف، وتم حل المشكلة.

الاستنتاج والمهام

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

هذا الرمز ليس أكثر من مثال لكيفية استخدام خطافات الويب S3 في أنشطتك. كما قلت في البداية، إذا كنت تخطط لاستخدام مثل هذا الخادم في الإنتاج، فأنت بحاجة على الأقل إلى إعادة كتابة الخادم للعمل غير المتزامن: تسجيل خطافات الويب الواردة في قائمة الانتظار (RabbitMQ أو NATS)، ومن هناك تحليلها ومعالجتها مع تطبيقات العمال. بخلاف ذلك، عندما تصل خطافات الويب على نطاق واسع، قد تواجه نقصًا في موارد الخادم لإكمال المهام. يتيح لك وجود قوائم الانتظار توزيع الخادم والعاملين، وكذلك حل المشكلات المتعلقة بالمهام المتكررة في حالة الفشل. يُنصح أيضًا بتغيير التسجيل إلى تسجيل أكثر تفصيلاً وأكثر توحيدًا.

حظا سعيدا!

المزيد من القراءة حول الموضوع:

المصدر: www.habr.com

إضافة تعليق