فيديو بالإنجليزية مع ترجمة عربية.
الجواب المختصر: نعم، لكن S3 طبقة واحدة من ثلاث
يؤدي تطبيق الدردشة ثلاث مهام مختلفة. فهو يوصل كل رسالة جديدة إلى جميع من في الغرفة لحظة إرسالها. وهو يتذكر الرسائل، فيرى من يفتح الغرفة آخر عشرات منها، ويستطيع التطبيق الإجابة عن أسئلة مثل «ما الذي لم أقرأه بعد». وهو يخزّن الملفات: الصور ومقاطع الفيديو القصيرة والرسائل الصوتية والمستندات التي يضعها المستخدمون في المحادثة.
تخزين الكائنات من نوع S3 ممتاز في المهمة الثالثة، ولم يُصمَّم للمهمتين الأوليين. لذلك فالجواب الصريح عن سؤال «هل أستطيع بناء دردشة على S3؟» هو نعم، على أن يكون S3 طبقة الملفات والأرشيف إلى جانب جزأين آخرين:
خادم تطبيق يُبقي اتصال WebSocket مفتوحًا مع كل عميل ويوزّع الرسائل. وهو صغير: بضع مئات من أسطر Node.js مع Socket.io تكفي لدردشة تعمل.
قاعدة بيانات تحفظ الرسائل صفوفًا، فيصبح «آخر 50 رسالة في هذه الغرفة» استعلامًا واحدًا على فهرس.
تخزين كائنات لكل ما هو ملف. يُبقي قاعدة البيانات والخادم خفيفين، لأن أيًّا منهما لا يحتاج إلى حفظ ميغابايتات من الوسائط أو نقلها.
يشرح باقي الدليل أين يقع الحد بين هذه الطبقات، ثم يربط الثلاث على CDNTR. يعمل التطبيق التجريبي في هذا الدليل مباشرة على CDNTR (Node.js وExpress وSocket.io): تم التحقق عليه بتاريخ 2026-11-06 من التطبيق وPostgres وربط الـ bucket والرفع والتنزيل بروابط موقَّعة. أما الأجزاء المذكورة كخيارات، أي Redis adapter ومهمة الأرشفة والخوادم الجاهزة، فلم تكن جزءًا من العرض التجريبي.
ما لا يستطيع S3 وحده فعله في الدردشة
لا يوجد push. يجيب S3 عن الطلبات ولا يبدأ أيًّا منها. عندما تصل رسالة جديدة، لا شيء يُخبر العملاء الآخرين. ومن دون خادم خاص بك سيضطرون إلى الاستطلاع المتكرر (polling): جلب قائمة كائنات الغرفة كل ثانية أو ثانيتين من كل تبويب مفتوح وكل هاتف. هذا بطيء في الإحساس، ويهدر الطلبات، ويبقى غير لحظي.
لا توجد إضافة (append). يُكتب الكائن دفعة واحدة؛ لا توجد عملية «أضف سطرًا إلى نهاية هذا الملف». لذا تصبح كل رسالة إما كائنًا مستقلًا (آلاف الكائنات الصغيرة لكل غرفة يوميًا)، وإما إعادة كتابة لكائن أكبر، يتسابق فيها مرسلان على الكتابة فوق نسخة كلٍّ منهما.
لا توجد استعلامات. يستطيع S3 سرد المفاتيح حسب البادئة (prefix)، وهذا كل شيء. «آخر 50 رسالة في هذه الغرفة»، «ما وصل منذ آخر زيارة لي»، «عدد غير المقروء»، «ابحث عن كلمة فاتورة»: كلها أسئلة لقاعدة البيانات. المفاتيح المرتبة زمنيًا تقطع بك جزءًا من الطريق ثم تتوقف.
لا يوجد مستخدمون ولا صلاحيات. يتحقق S3 من شيء واحد: هل الطلب موقَّع بمفتاح صالح. من في أي غرفة، ومن يحق له رؤية أي ملف، ومن محظور: هذا المنطق يخص تطبيقك. وتسليم مفاتيح S3 للمتصفح كي يقرأ ويكتب مباشرة يعني منح كل مستخدم وصولًا إلى الـ bucket كله.
لا شيء من ذلك عيب في S3. إنه مخزن ملفات، والدردشة محادثة لحظية ذات حالة. استخدم كل أداة فيما صُنعت له.
فيمَ يتفوق S3 داخل تطبيق الدردشة
المرفقات. صور وفيديو ورسائل صوتية وملفات PDF. هي كبيرة، تُكتب مرة وتُقرأ مرات كثيرة: وهذا بالضبط ما صُنع له تخزين الكائنات. لا تحفظ قاعدة البيانات لكل رسالة سوى مفتاح واسم ملف، فتبقى صغيرة وسريعة مهما كثرت الوسائط المشتركة.
أرشيف الرسائل. المحادثات القديمة نادرًا ما تُقرأ، لكن يجب ألا تضيع. نقلها من قاعدة البيانات إلى S3 في كتل مضغوطة (كتلة لكل غرفة في كل يوم مثلًا) يُبقي الجدول النشط صغيرًا دون أن يضيع شيء من السجل.
التصدير والنسخ الاحتياطي. «نزّل بياناتي»، وتصدير غرفة، ونسخ قاعدة البيانات الليلية: كل منها ملف، ومكان كل منها bucket.
خادم تطبيق أخف. لأن المتصفح يرفع الملفات مباشرة إلى S3 وينزّلها منه مباشرة (توضح الأقسام التالية كيف)، لا يمرّر الخادم أي وسائط عبره. هو يوقّع روابط قصيرة العمر وينقل رسائل JSON صغيرة، لذلك تكفي حاوية صغيرة واحدة لمدى بعيد.
على CDNTR، تخزّن خدمة S3 على العنوان s3.cdn.com.tr الكائنات في مراكز بياناتنا في تركيا، وهي متوافقة مع S3: تعمل حزم AWS SDK معها عبر endpoint مخصص وعنونة path-style.
البنية على CDNTR والتجهيز عبر cdnctl
التطبيق يعمل على Managed Container Apps. العرض التجريبي تطبيق Node.js مع Express وSocket.io، نُشر من مجلد الشيفرة المصدرية بالأمر cdnctl deploy: تُبنى الصورة داخل العنقود، فلا حاجة إلى registry. يحصل التطبيق على عنوان مثل https://xxxx.cdn.com.tr، وتمر حركة WebSocket الخاصة به عبر الـ CDN (في العرض التجريبي أبلغ Socket.io أن وسيلة النقل websocket). إن كانت الحاويات جديدة عليك، فدليل حاوية Docker على CDN يغطي الأساسيات.
قاعدة البيانات هي إضافة Postgres المُدارة. عند تفعيلها مع --env-prefix DATABASE تمنح التطبيق DATABASE_HOST وDATABASE_PORT وDATABASE_NAME وDATABASE_USER والسر DATABASE_PASSWORD.
الملفات تقيم في bucket على تخزين الكائنات. تنشئ الـ bucket ومفتاح وصول خاصًا به، ثم تربطهما بالتطبيق مع --env-prefix S3. يحصل التطبيق على S3_ENDPOINT (https://s3.cdn.com.tr) وS3_BUCKET وS3_REGION (cdn-tr) وS3_ACCESS_KEY_ID والسر S3_SECRET_ACCESS_KEY. المفاتيح موجودة في بيئة التطبيق فقط، ولا تصل إلى المتصفح أبدًا.
التجهيز كله أربع خطوات. استبدل <account> و<app> و<bucket> و<key> بالمعرّفات التي تطبعها الأوامر السابقة.
# 1. deploy the app from source (built in the cluster, no registry)
cdnctl deploy --dir . --account <account> --name chat-demo --healthcheck /health
# 2. managed Postgres -> DATABASE_HOST, _PORT, _NAME, _USER, _PASSWORD
cdnctl container addons enable-postgres --account <account> --app <app> --env-prefix DATABASE
# 3. a bucket and an access key for it
cdnctl object-storage buckets create --account <account> --name chat-demo-files
cdnctl object-storage access-keys create --account <account> --bucket <bucket>
# 4. bind them -> S3_ENDPOINT, S3_BUCKET, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY
cdnctl object-storage bindings create --account <account> --app <app> \
--bucket <bucket> --access-key <key> --env-prefix S3
الرسائل: جدول في Postgres ومعالج في Socket.io
الرسالة صف: الغرفة، والكاتب، والنص، وللمرفقات مفتاح الكائن واسم الملف الأصلي. الفهرس على (room, id) يحوّل الاستعلام الذي تنفّذه الدردشة باستمرار، أي آخر 50 رسالة في غرفة، إلى مسح قصير للفهرس مهما كبر الجدول.
جانب Socket.io حدثان فقط. مع join يدخل العميل غرفة ويتلقى سجلها. ومع message يكتب الخادم الصف أولًا، ثم يبث الصف المحفوظ إلى كل من في الغرفة، بمن فيهم المرسل. بثّ ما أعادته قاعدة البيانات، لا ما أرسله العميل، يمنح الجميع id نفسه والطابع الزمني نفسه؛ والرسالة التي لم تُحفظ لا تصل إلى أحد.
يضبط socket.data.user الـ middleware الخاص بالمصادقة لديك عند فتح الاتصال. لا يحدد العميل هويته بنفسه داخل محتوى الرسالة أبدًا.
يعمل العرض التجريبي بنسخة واحدة (replica). مع عدة نسخ، يجب أن تصل الرسالة أيضًا إلى العملاء المتصلين بالنسخ الأخرى؛ والطريقة المعتادة إضافة Redis المُدارة (cdnctl container addons enable-redis) مع Redis adapter الخاص بـ Socket.io. وعن Redis نفسه اقرأ ما هو Redis.
المخطط ومعالج الرسائل (Postgres، socket.io 4)
-- messages table
CREATE TABLE IF NOT EXISTS messages (
id bigserial PRIMARY KEY,
room text NOT NULL,
author text NOT NULL,
body text,
file_key text,
file_name text,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS messages_room_id ON messages (room, id);
// server.js (socket.io 4)
io.on('connection', (socket) => {
socket.on('join', async (room) => {
socket.join(room);
const { rows } = await db.query(
`SELECT * FROM (SELECT * FROM messages WHERE room = $1
ORDER BY id DESC LIMIT 50) last50 ORDER BY id`, [room]);
socket.emit('history', rows);
});
socket.on('message', async ({ room, body, fileKey, fileName }) => {
const { rows } = await db.query(
`INSERT INTO messages (room, author, body, file_key, file_name)
VALUES ($1, $2, $3, $4, $5) RETURNING *`,
[room, socket.data.user, body ?? null, fileKey ?? null, fileName ?? null]);
io.to(room).emit('message', rows[0]); // everyone in the room, at once
});
});
الرفع: روابط موقَّعة، من المتصفح مباشرة إلى S3
تمرير الملفات عبر خادم التطبيق يجعله عنق الزجاجة: تُرفع كل صورة مرتين وتستهلك الذاكرة وعرض النطاق في الطريق. بدلًا من ذلك يمنح التطبيق الإذن ثم يتنحّى جانبًا.
1. يطلب المتصفح من التطبيق رابط رفع، مرسلًا نوع الملف وحجمه. يتحقق التطبيق من المستخدم والغرفة والحجم (يسمح العرض التجريبي بما يصل إلى 10 ميغابايت)، ويختار مفتاحًا مثل rooms/<room>/<uuid>، ويعيد رابط PUT موقَّعًا قصير العمر صالحًا لمدة 5 دقائق.
2. يرسل المتصفح الملف بـ PUT مباشرة إلى S3 عبر هذا الرابط.
3. يرسل المتصفح رسالة الدردشة مع مفتاح الكائن؛ ويحفظها الخادم كأي رسالة أخرى.
4. لفتح ملف، يستدعي المستلم التطبيق، فيتحقق من الصلاحية ثم يعيد التوجيه إلى رابط GET موقَّع صالح أيضًا لمدة 5 دقائق.
الرابط الموقَّع طلب S3 عادي يحمل توقيعه في سلسلة الاستعلام: من يملكه يستطيع تنفيذ تلك العملية بالضبط، على ذلك المفتاح وحده، حتى تنتهي صلاحيته. يشرح دليل الروابط الموقَّعة الفكرة بتفصيل أكبر. يتحقق التطبيق من الحجم المُعلَن قبل التوقيع؛ أبقِ الحد ومدة الصلاحية وصيغة المفتاح على الخادم، حيث لا يستطيع المستخدمون تغييرها.
رابط PUT موقَّع مع Content-Type موقَّع، وإعادة توجيه التنزيل
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { randomUUID } from 'node:crypto';
const s3 = new S3Client({
endpoint: process.env.S3_ENDPOINT, // https://s3.cdn.com.tr
region: process.env.S3_REGION, // cdn-tr
forcePathStyle: true,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
});
const MAX_BYTES = 10 * 1024 * 1024;
app.post('/api/upload-url', express.json(), async (req, res) => {
const { room, type, size } = req.body;
if (!type || !(size > 0) || size > MAX_BYTES) {
return res.status(400).json({ error: 'max 10 MB' });
}
const key = `rooms/${room}/${randomUUID()}`;
const url = await getSignedUrl(s3,
new PutObjectCommand({ Bucket: process.env.S3_BUCKET, Key: key, ContentType: type }),
{ expiresIn: 300, signableHeaders: new Set(['content-type']) });
res.json({ url, key });
});
app.get('/api/files', async (req, res) => {
// check here that the user may read this room
const url = await getSignedUrl(s3,
new GetObjectCommand({ Bucket: process.env.S3_BUCKET, Key: req.query.key }),
{ expiresIn: 300 });
res.redirect(302, url);
});
فخ Content-Type: الخطأ 403 AccessDenied على رابط PUT موقَّع
هذه النقطة تكلّف الناس عادة فترة ما بعد الظهر كاملة، لذلك أفردنا لها قسمًا. تعمل خدمة S3 لدينا على Ceph RGW، وRGW أكثر صرامة من AWS في ترويسة واحدة: إذا أرسل المتصفح Content-Type لا يغطيه التوقيع، يُرفض الـ PUT الموقَّع بـ 403 AccessDenied. أما AWS فيتجاهل هذه الترويسة حين لا تكون موقَّعة، ولذلك قد تفشل هنا شيفرة تعمل هناك، بخطأ يبدو كأنه مشكلة في المفاتيح.
الحل أن توقّع النوع داخل الرابط ثم ترسل النوع نفسه تمامًا. مع AWS SDK v3 مرّر ContentType في PutObjectCommand وأضف signableHeaders: new Set(['content-type']) إلى getSignedUrl، كما في المقتطف أعلاه. وفي المتصفح ضع ترويسة Content-Type نفسها على طلب PUT.
تفصيلتان تجعلان ذلك موثوقًا. استخدم القيمة الاحتياطية نفسها في الطرفين: الملف الذي لا نوع له (file.type سلسلة فارغة) يجب أن يُوقَّع ويُرسَل بالقيمة نفسها، مثل application/octet-stream. ولا تدع مكتبة تعيد كتابة الترويسة: بعض أدوات الرفع تضيف ; charset=utf-8 إلى الملفات النصية، فلا تعود مطابقة للتوقيع.
جانب المتصفح: النوع نفسه الذي وقّعه الخادم
// browser: ask for a URL, PUT the file to S3, then send the message
const { url, key } = await fetch('/api/upload-url', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ room, type: file.type || 'application/octet-stream', size: file.size }),
}).then((r) => r.json());
const put = await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': file.type || 'application/octet-stream' }, // exactly the signed type
body: file,
});
if (!put.ok) throw new Error(`upload failed: ${put.status}`);
socket.emit('message', { room, fileKey: key, fileName: file.name });
CORS على الـ bucket
تعمل الصفحة على عنوان تطبيقك، بينما يذهب الرفع إلى s3.cdn.com.tr، أي إلى أصل (origin) مختلف. لذلك يرسل المتصفح طلب preflight قبل الـ PUT، ولا يكمل إلا إذا ردّ الـ bucket بقاعدة CORS تسمح بأصل تطبيقك وبالطريقة PUT وبالترويسة Content-Type. من دونها يفشل الرفع في المتصفح بينما ينجح الطلب نفسه عبر curl، وهذه العلامة الكلاسيكية لغياب قاعدة CORS.
تُضبط قواعد CORS للـ bucket عبر S3 API باستخدام PutBucketCors. يفعل العرض التجريبي ذلك مرة واحدة عند الإقلاع، فتبقى القاعدة بجوار الشيفرة التي تعتمد عليها. اسمح لأصلك أنت، لا لـ *: القاعدة جزء مما يمنع المواقع الأخرى من استخدام الـ bucket الخاص بك من صفحاتها. يشرح دليل ما هو CORS طلبات preflight ورسائل الخطأ الشائعة بالتفصيل.
قاعدة CORS للـ bucket من أجل الرفع والتنزيل المباشرين
import { PutBucketCorsCommand } from '@aws-sdk/client-s3';
// once at startup: let the app's own origin PUT and GET directly
await s3.send(new PutBucketCorsCommand({
Bucket: process.env.S3_BUCKET,
CORSConfiguration: {
CORSRules: [{
AllowedOrigins: ['https://xxxx.cdn.com.tr'], // your app's address
AllowedMethods: ['PUT', 'GET'],
AllowedHeaders: ['content-type'],
MaxAgeSeconds: 3600,
}],
},
}));
WebSocket عبر الـ CDN: مهلة الخمول وإعادة الاتصال
ينقل الـ CDN اتصالات WebSocket على مستوى قاعدة التوصيل. على نطاق Managed Container Apps يكون WebSocket مفعّلًا افتراضيًا، بمهلة خمول قدرها 300 ثانية ما لم تحدد قاعدة التوصيل قيمة أخرى؛ ويمكن للقاعدة أن تحدد أي قيمة بين 1 و3600 ثانية. تحسب المهلة الصمت لا المدة الكلية؛ فالاتصال الذي تستمر فيه البيانات يبقى مفتوحًا. يرسل Socket.io افتراضيًا نبضة (heartbeat) خاصة به كل 25 ثانية، ما يُبقي حتى الغرفة الهادئة ضمن القيمة الافتراضية بفارق واسع. الإعدادات موضحة في دليل الاتصال بخادم المصدر.
يجب أن يعيد العملاء الاتصال بأنفسهم. قد تُغلق اتصالات WebSocket المفتوحة عند إعادة تحميل إعدادات الـ edge، والهواتف تفقد الاتصال كلما بدّلت الشبكة. يعيد Socket.io الاتصال تلقائيًا؛ وإن كنت تستخدم WebSocket الخام فأضف إعادة اتصال مع backoff.
بعد إعادة الاتصال ينبغي للعميل أن يجلب ما فاته. أبسط طريقة إرسال join مجددًا: يرد الخادم بالسجل الأخير للغرفة، ويدمجه العميل حسب id الرسالة، فلا يظهر شيء مرتين.
أرشفة الرسائل القديمة، أو استخدام خادم دردشة جاهز
الأرشفة. يحتفظ العرض التجريبي بكل الرسائل في Postgres، وهذا مناسب لوقت طويل. وحين يكبر الجدول، فإن نمطًا شائعًا هو مهمة دورية تأخذ الرسائل الأقدم من 90 يومًا مثلًا، وتكتبها في S3 على شكل كتلة JSON لكل غرفة في كل يوم (archive/<room>/2026-08-01.json.gz)، ثم تحذف تلك الصفوف. ويقرأ «تحميل الرسائل الأقدم» الكتلة المناسبة من S3 عبر GET موقَّع. تحتفظ قاعدة البيانات بما يتصفحه الناس فعلًا، ويحتفظ S3 بالباقي.
الخوادم الجاهزة. إن كنت تفضّل ألا تكتب دردشتك بنفسك، فإن Mattermost وRocket.Chat وMatrix Synapse تستطيع تخزين الملفات المرفوعة على تخزين متوافق مع S3. والطبقات الثلاث نفسها تنطبق هناك: عملية الخادم الخاصة بها، وقاعدة بياناتها، وbucket للملفات. وعلى CDNTR يعني ذلك الحاوية وإضافة قاعدة البيانات والـ bucket من هذا الدليل، مضبوطة بنقطة النهاية والـ bucket والمفاتيح التي تطلبها وثائق كل مشروع.
قائمة تحقق: الأخطاء التي تُفسد رفع الملفات في الدردشة
قاعدة CORS على الـ bucket. أصل تطبيقك، وPUT وGET، وترويسة Content-Type. إن غابت فلن تراها إلا رفعًا فاشلًا في المتصفح.
Content-Type موقَّع. وقّعه داخل رابط PUT وأرسل القيمة نفسها تمامًا، مع القيمة الاحتياطية نفسها للملفات التي لا نوع لها. وإلا: 403 AccessDenied.
صلاحية قصيرة. دقائق لا أيام. يستخدم العرض التجريبي 5 دقائق لكل من PUT وGET؛ فيصبح الرابط المسرَّب عديم الفائدة على الفور تقريبًا.
الملفات لا تمر عبر التطبيق. الرفع والتنزيل مباشرة بين المتصفح وS3. التطبيق يوقّع ويعيد التوجيه، ولا ينقل البيانات.
إعادة الاتصال التلقائية. توقّع أن تُغلق اتصالات WebSocket وتُفتح من جديد. انضم إلى الغرفة مجددًا وادمج السجل حسب id الرسالة.
حدود الحجم. تحقق من الحجم المُعلَن قبل التوقيع وارفض ما يتجاوز حدك (10 ميغابايت في العرض التجريبي).
المفاتيح تبقى على الخادم. تعيش مفاتيح وصول S3 في بيئة التطبيق بفضل الربط. لا ترسلها إلى المتصفح أبدًا ولا تضمّنها في شيفرة العميل؛ فالمتصفح لا يرى إلا الروابط الموقَّعة.
التحقق من الصلاحية عند التنزيل. مرّر روابط الملفات عبر التطبيق، ليتأكد قبل إعادة التوجيه أن المستخدم يحق له رؤية تلك الغرفة.
كيفية الإعداد
أدلة خطوة بخطوة في مركز المساعدة:
أسئلة شائعة حول تطبيق دردشة مع S3
هل يمكن بناء تطبيق دردشة بـ S3 وحده؟
ليس تطبيقًا لحظيًا. لا يستطيع S3 دفع الرسائل الجديدة ولا الإضافة إلى الكائنات ولا الاستعلام عنها، فيضطر العملاء إلى الاستطلاع المتكرر، وتجد نفسك تعيد بناء قاعدة بيانات فوق قوائم المفاتيح. استخدم S3 للملفات والأرشيف، وقاعدة بيانات للرسائل، وخادم WebSocket صغيرًا للإيصال.
لماذا لا يستطلع العملاء S3 بحثًا عن الرسائل الجديدة؟
سيجلب كل عميل مفتوح قائمة الكائنات كل ثانية أو ثانيتين: هذا بطيء في الإحساس، ويضاعف الطلبات، ولا يجيب مع ذلك عن «آخر 50» و«غير المقروء». أما اتصال WebSocket فيوصل الرسالة إلى كل من في الغرفة لحظة أن يحفظها الخادم.
هل تمر الملفات المرفوعة عبر خادم تطبيقي؟
لا. يعيد التطبيق رابط PUT موقَّعًا صالحًا 5 دقائق في العرض التجريبي، ويرفع المتصفح الملف مباشرة إلى S3. والتنزيل يعمل بالطريقة نفسها: يتحقق التطبيق من الصلاحية ثم يعيد التوجيه إلى رابط GET موقَّع.
لماذا يعيد رابط PUT الموقَّع الخطأ 403 AccessDenied؟
في S3 لدينا السبب الأكثر شيوعًا ترويسة Content-Type لا يغطيها التوقيع. وقّعها داخل الرابط (مع AWS SDK v3: ContentType في PutObjectCommand وsignableHeaders: new Set(['content-type'])) وأرسل النوع نفسه تمامًا من المتصفح. وإن أظهر المتصفح بدلًا من ذلك خطأ CORS، فالـ bucket يحتاج إلى قاعدة CORS.
هل يعمل WebSocket عبر الـ CDN؟
نعم. على نطاق Managed Container Apps يكون WebSocket مفعّلًا افتراضيًا، بمهلة خمول قدرها 300 ثانية ما لم تحدد قاعدة التوصيل قيمة أخرى (يمكن للقاعدة أن تحدد بين 1 و3600 ثانية). يجب أن يعيد العملاء الاتصال تلقائيًا، لأن الاتصالات المفتوحة قد تُغلق عند إعادة تحميل إعدادات الـ edge؛ ويفعل Socket.io ذلك بنفسه.
هل أحتاج إلى Redis لدردشة مبنية على Socket.io؟
ليس مع نسخة واحدة؛ والعرض التجريبي يعمل بنسخة واحدة. مع عدة نسخ يجب أن تصل الرسالة إلى العملاء المتصلين بالنسخ الأخرى، والطريقة المعتادة إضافة Redis المُدارة مع Redis adapter الخاص بـ Socket.io.