feat: add safe miner control foundation
This commit is contained in:
1 parent
6cd876b4b3
commit
f5965af914
39 files changed
+2952
-491
No files matched your search
@@ -0,0 +1,137 @@
|
||||
"""add miner control foundation
|
||||
|
||||
Revision ID: 0015_miner_control_foundation
|
||||
Revises: 0014_repair_parts_tracking
|
||||
Create Date: 2026-08-24
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
|
||||
revision: str = "0015_miner_control_foundation"
|
||||
down_revision: Union[str, None] = "0014_repair_parts_tracking"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
QUEUE_STATUSES = ("pending", "claimed", "completed", "failed", "cancelled")
|
||||
|
||||
|
||||
def _format_values(values: object) -> str:
|
||||
return ", ".join(str(value) for value in (values or []))
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
connection = op.get_bind()
|
||||
unknown_statuses = connection.execute(
|
||||
sa.text(
|
||||
"""
|
||||
SELECT array_agg(DISTINCT command_status ORDER BY command_status)
|
||||
FROM minerops_agent_command_queue
|
||||
WHERE command_status NOT IN ('pending', 'claimed', 'completed', 'failed', 'cancelled')
|
||||
"""
|
||||
),
|
||||
).scalar()
|
||||
if unknown_statuses:
|
||||
raise RuntimeError(
|
||||
"Cannot upgrade to 0015: minerops_agent_command_queue contains "
|
||||
f"unsupported command_status values: {_format_values(unknown_statuses)}. "
|
||||
"Correct those rows to pending, claimed, completed, failed, or cancelled "
|
||||
"before retrying the migration."
|
||||
)
|
||||
|
||||
duplicate_live_miners = connection.execute(
|
||||
sa.text(
|
||||
"""
|
||||
SELECT request_payload ->> 'miner_id' AS miner_id
|
||||
FROM minerops_agent_command_queue
|
||||
WHERE command_type = 'miner_control'
|
||||
AND command_status IN ('pending', 'claimed')
|
||||
AND nullif(trim(request_payload ->> 'miner_id'), '') IS NOT NULL
|
||||
GROUP BY request_payload ->> 'miner_id'
|
||||
HAVING count(*) > 1
|
||||
ORDER BY request_payload ->> 'miner_id'
|
||||
"""
|
||||
)
|
||||
).scalars().all()
|
||||
if duplicate_live_miners:
|
||||
raise RuntimeError(
|
||||
"Cannot upgrade to 0015: more than one pending or claimed miner_control "
|
||||
"command exists for miner UUID(s): "
|
||||
f"{_format_values(duplicate_live_miners)}. Resolve or cancel the duplicate "
|
||||
"live commands before retrying the migration; no queue history was changed."
|
||||
)
|
||||
|
||||
op.add_column(
|
||||
"minerops_site_agents",
|
||||
sa.Column("site_id", postgresql.UUID(as_uuid=True), nullable=True),
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"fk_minerops_site_agents_site_id",
|
||||
"minerops_site_agents",
|
||||
"sites",
|
||||
["site_id"],
|
||||
["id"],
|
||||
ondelete="RESTRICT",
|
||||
)
|
||||
op.create_index(
|
||||
"uq_minerops_site_agents_site_id",
|
||||
"minerops_site_agents",
|
||||
["site_id"],
|
||||
unique=True,
|
||||
postgresql_where=sa.text("site_id IS NOT NULL"),
|
||||
)
|
||||
op.create_check_constraint(
|
||||
"ck_minerops_agent_command_queue_status",
|
||||
"minerops_agent_command_queue",
|
||||
"command_status IN ('pending', 'claimed', 'completed', 'failed', 'cancelled')",
|
||||
)
|
||||
op.create_index(
|
||||
"uq_agent_queue_live_miner_control",
|
||||
"minerops_agent_command_queue",
|
||||
[sa.text("(request_payload ->> 'miner_id')")],
|
||||
unique=True,
|
||||
postgresql_where=sa.text(
|
||||
"command_type = 'miner_control' "
|
||||
"AND command_status IN ('pending', 'claimed')"
|
||||
),
|
||||
)
|
||||
op.create_index(
|
||||
"idx_agent_queue_miner_control_history",
|
||||
"minerops_agent_command_queue",
|
||||
[
|
||||
sa.text("(request_payload ->> 'miner_id')"),
|
||||
sa.text("created_at DESC"),
|
||||
sa.text("id DESC"),
|
||||
],
|
||||
postgresql_where=sa.text("command_type = 'miner_control'"),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(
|
||||
"idx_agent_queue_miner_control_history",
|
||||
table_name="minerops_agent_command_queue",
|
||||
)
|
||||
op.drop_index(
|
||||
"uq_agent_queue_live_miner_control",
|
||||
table_name="minerops_agent_command_queue",
|
||||
)
|
||||
op.drop_constraint(
|
||||
"ck_minerops_agent_command_queue_status",
|
||||
"minerops_agent_command_queue",
|
||||
type_="check",
|
||||
)
|
||||
op.drop_index(
|
||||
"uq_minerops_site_agents_site_id",
|
||||
table_name="minerops_site_agents",
|
||||
)
|
||||
op.drop_constraint(
|
||||
"fk_minerops_site_agents_site_id",
|
||||
"minerops_site_agents",
|
||||
type_="foreignkey",
|
||||
)
|
||||
op.drop_column("minerops_site_agents", "site_id")
|
||||
Reference in new issue
Block a user