Merge branch 'refactor/remove-redis' into develop

# Conflicts:
#	.env.example
#	CLAUDE.md
#	backend/Dockerfile
#	backend/pyproject.toml
#	backend/src/backend/main.py
#	backend/src/backend/schedule_runs.py
#	common/src/common/db/models.py
#	common/src/common/eventing.py
#	contracts/README.md
#	contracts/demo-core-v1.md
#	contracts/events/README.md
#	contracts/events/event-envelope-v1.json
#	contracts/locks/README.md
#	contracts/locks/file-edit-lock-v1.md
#	contracts/schedules/schedule-definition-api-v1.md
#	docker-compose.yml
#	frontend/README.md
#	migrations/README.md
#	migrations/versions/20260724_0001_v1_schema_baseline.py
#	runtime/Dockerfile
#	runtime/README.md
#	runtime/pyproject.toml
#	runtime/src/runtime/main.py
#	schedule/Dockerfile
#	schedule/README.md
#	schedule/pyproject.toml
#	schedule/src/schedule/main.py
#	schedule/src/schedule/service.py
This commit is contained in:
tao.chen
2026-07-30 20:14:53 +08:00
65 changed files with 12108 additions and 659 deletions
+5 -5
View File
@@ -14,14 +14,14 @@ class ConsumerInbox(Base):
__tablename__ = 'consumer_inbox'
__table_args__ = (
Index('idx_consumer_inbox_status', 'consumer_name', 'process_status', 'created_at'),
{'comment': '消费者幂等 Inbox,防止 Stream 重投导致重复执行'}
{'comment': '消费者幂等 Inbox,防止数据库事件重复处理'}
)
consumer_name: Mapped[str] = mapped_column(String(128), primary_key=True)
event_id: Mapped[str] = mapped_column(CHAR(26), primary_key=True)
process_status: Mapped[str] = mapped_column(String(16), nullable=False, server_default=text("'processing'"), comment='processing/succeeded/failed')
created_at: Mapped[datetime.datetime] = mapped_column(DATETIME(fsp=3), nullable=False, server_default=text('CURRENT_TIMESTAMP(3)'))
message_id: Mapped[Optional[str]] = mapped_column(String(128), comment='Redis Stream message ID')
message_id: Mapped[Optional[str]] = mapped_column(String(128), comment='数据库事件处理批次标识')
processed_at: Mapped[Optional[datetime.datetime]] = mapped_column(DATETIME(fsp=3))
error_message: Mapped[Optional[str]] = mapped_column(String(2000))
@@ -32,7 +32,7 @@ class OutboxEvents(Base):
Index('idx_outbox_aggregate', 'aggregate_type', 'aggregate_id', 'created_at'),
Index('idx_outbox_idempotency', 'idempotency_key'),
Index('idx_outbox_pending', 'event_status', 'available_at', 'created_at'),
{'comment': '事务 Outbox提交后发布到 Redis Streams'}
{'comment': '事务 Outbox由 Schedule Executor 直接轮询处理'}
)
event_id: Mapped[str] = mapped_column(CHAR(26), primary_key=True)
@@ -432,14 +432,14 @@ class EditSessions(Base):
Index('idx_edit_sessions_object', 'storage_object_id', 'session_status', 'expires_at'),
Index('idx_edit_sessions_runtime', 'runtime_id', 'session_status'),
Index('idx_edit_sessions_user', 'user_id', 'session_status'),
{'comment': '编辑会话审计;实时锁状态以 Redis 为准'}
{'comment': '编辑会话与数据库租约;MySQL 为锁状态权威'}
)
edit_session_id: Mapped[str] = mapped_column(CHAR(26), primary_key=True)
workspace_id: Mapped[str] = mapped_column(CHAR(26), nullable=False)
storage_object_id: Mapped[str] = mapped_column(CHAR(26), nullable=False)
user_id: Mapped[str] = mapped_column(CHAR(26), nullable=False)
redis_lock_key: Mapped[str] = mapped_column(String(512), nullable=False)
lock_key: Mapped[str] = mapped_column(String(512), nullable=False)
lock_token_hash: Mapped[bytes] = mapped_column(BINARY(32), nullable=False, comment='不保存原始 token')
session_status: Mapped[str] = mapped_column(String(16), nullable=False, server_default=text("'active'"), comment='active/closed/expired/failed')
started_at: Mapped[datetime.datetime] = mapped_column(DATETIME(fsp=3), nullable=False, server_default=text('CURRENT_TIMESTAMP(3)'))
+5 -5
View File
@@ -9,10 +9,10 @@ from common.db.models import OutboxEvents
from common.ids import new_ulid
STREAM_BY_EVENT_TYPE = {
"schedule.run.requested": "stream:scheduler:commands",
"job.node.execute": "stream:jobs:execute",
"job.node.finished": "stream:jobs:results",
SUPPORTED_EVENT_TYPES = {
"schedule.run.requested",
"job.node.execute",
"job.node.finished",
}
@@ -39,7 +39,7 @@ async def add_outbox_event(
payload: dict[str, Any],
available_at: datetime | None = None,
) -> OutboxEvents:
if event_type not in STREAM_BY_EVENT_TYPE:
if event_type not in SUPPORTED_EVENT_TYPES:
raise ValueError(f"unsupported event type: {event_type}")
event_id = new_ulid()
envelope = {