feat: complete IM P0 and P1 reliability work

This commit is contained in:
richjohnrambo
2026-08-17 13:43:27 +08:00
parent ddf0f7a55e
commit f2c229135b
43 changed files with 4512 additions and 1181 deletions
+54 -16
View File
@@ -159,6 +159,44 @@ CREATE TABLE IF NOT EXISTS tinode.im_system_notifications (
INDEX idx_im_system_notifications_inbox (user_id, id DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE IF NOT EXISTS tinode.im_http_idempotency (
id BIGINT NOT NULL AUTO_INCREMENT,
user_id BIGINT NOT NULL,
method VARCHAR(8) NOT NULL,
route VARCHAR(512) NOT NULL,
idempotency_key VARCHAR(128) NOT NULL,
body_hash CHAR(64) NOT NULL,
state VARCHAR(16) NOT NULL DEFAULT 'processing',
response_status INT NOT NULL DEFAULT 0,
response_body MEDIUMBLOB,
expires_at DATETIME(3) NOT NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE INDEX uk_im_http_idempotency_scope (user_id, method, route, idempotency_key),
INDEX idx_im_http_idempotency_expiry (expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE IF NOT EXISTS tinode.im_business_events_outbox (
id BIGINT NOT NULL AUTO_INCREMENT,
event_id VARCHAR(64) NOT NULL,
target_type VARCHAR(16) NOT NULL,
target VARCHAR(128) NOT NULL,
actor_user_id BIGINT NOT NULL DEFAULT 0,
event_type VARCHAR(64) NOT NULL,
payload JSON,
status VARCHAR(16) NOT NULL DEFAULT 'pending',
attempts INT NOT NULL DEFAULT 0,
next_retry_at DATETIME(3),
delivered_at DATETIME(3),
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE INDEX uk_im_business_events_outbox_event (event_id),
INDEX idx_im_business_events_outbox_pending (status, next_retry_at, id),
INDEX idx_im_business_events_outbox_target (target_type, target, id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE IF NOT EXISTS tinode.im_message_revisions (
id BIGINT NOT NULL AUTO_INCREMENT,
createdat DATETIME(3) NOT NULL,
@@ -239,11 +277,11 @@ CREATE TABLE IF NOT EXISTS tinode.im_favorites (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- Existing Tinode tables must match the current schema for chapters 2-7:
-- topics.aux, fileuploads.etag, and filemsglinks.topic/userid are required by current code.
-- im_topics.aux, im_fileuploads.etag, and im_filemsglinks.topic/userid are required by current code.
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'messages' AND COLUMN_NAME = 'client_msg_id') = 0,
'ALTER TABLE tinode.messages ADD COLUMN client_msg_id VARCHAR(64) AFTER `from`',
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'im_messages' AND COLUMN_NAME = 'client_msg_id') = 0,
'ALTER TABLE tinode.im_messages ADD COLUMN client_msg_id VARCHAR(64) AFTER `from`',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
@@ -251,8 +289,8 @@ EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'messages' AND COLUMN_NAME = 'version') = 0,
'ALTER TABLE tinode.messages ADD COLUMN version INT NOT NULL DEFAULT 1 AFTER client_msg_id',
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'im_messages' AND COLUMN_NAME = 'version') = 0,
'ALTER TABLE tinode.im_messages ADD COLUMN version INT NOT NULL DEFAULT 1 AFTER client_msg_id',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
@@ -260,8 +298,8 @@ EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'messages' AND COLUMN_NAME = 'recalled_at') = 0,
'ALTER TABLE tinode.messages ADD COLUMN recalled_at DATETIME(3) AFTER version',
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'im_messages' AND COLUMN_NAME = 'recalled_at') = 0,
'ALTER TABLE tinode.im_messages ADD COLUMN recalled_at DATETIME(3) AFTER version',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
@@ -269,8 +307,8 @@ EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'messages' AND COLUMN_NAME = 'recalled_by') = 0,
'ALTER TABLE tinode.messages ADD COLUMN recalled_by BIGINT AFTER recalled_at',
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'im_messages' AND COLUMN_NAME = 'recalled_by') = 0,
'ALTER TABLE tinode.im_messages ADD COLUMN recalled_by BIGINT AFTER recalled_at',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
@@ -278,8 +316,8 @@ EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'messages' AND INDEX_NAME = 'messages_sender_client_mid') = 0,
'CREATE UNIQUE INDEX messages_sender_client_mid ON tinode.messages(`from`, client_msg_id)',
(SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'im_messages' AND INDEX_NAME = 'messages_sender_client_mid') = 0,
'CREATE UNIQUE INDEX messages_sender_client_mid ON tinode.im_messages(`from`, client_msg_id)',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
@@ -291,8 +329,8 @@ DROP TABLE IF EXISTS tinode.im_tenant_config;
DROP TABLE IF EXISTS tinode.im_tenant;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'auth' AND COLUMN_NAME = 'tenant_id') > 0,
'ALTER TABLE tinode.auth DROP COLUMN tenant_id',
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'im_auth' AND COLUMN_NAME = 'tenant_id') > 0,
'ALTER TABLE tinode.im_auth DROP COLUMN tenant_id',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
@@ -300,8 +338,8 @@ EXECUTE im_stmt;
DEALLOCATE PREPARE im_stmt;
SET @im_sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'credentials' AND COLUMN_NAME = 'tenant_id') > 0,
'ALTER TABLE tinode.credentials DROP COLUMN tenant_id',
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'tinode' AND TABLE_NAME = 'im_credentials' AND COLUMN_NAME = 'tenant_id') > 0,
'ALTER TABLE tinode.im_credentials DROP COLUMN tenant_id',
'SELECT 1'
);
PREPARE im_stmt FROM @im_sql;
@@ -732,4 +770,4 @@ VALUES (1, '["bug","suggestion","complaint","other"]', 1000, '{"max_files":5,"pu
ON DUPLICATE KEY UPDATE updated_at = updated_at;
-- Current MySQL adapter schema version expected by server/db/mysql/adapter.go.
UPDATE tinode.kvmeta SET `value` = 123 WHERE `key` = 'version';
UPDATE tinode.im_kvmeta SET `value` = 123 WHERE `key` = 'version';