Update edge-api systemd service paths, switch to SQLite, add timezone-aware datetimes, and make job payments optional for proof-of-concept
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Waiting to run
Production Tests / Production Integration Tests (push) Waiting to run
Coverage Phase 1 (70% Target) / test-coverage-70 (push) Has been cancelled
Coverage Phase 2 (85% Target) / test-coverage-85 (push) Has been cancelled
Cross-Node Transaction Testing / transaction-test (push) Has been cancelled
Deploy to Testnet / deploy-testnet (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Waiting to run
Production Tests / Production Integration Tests (push) Waiting to run
Coverage Phase 1 (70% Target) / test-coverage-70 (push) Has been cancelled
Coverage Phase 2 (85% Target) / test-coverage-85 (push) Has been cancelled
Cross-Node Transaction Testing / transaction-test (push) Has been cancelled
Deploy to Testnet / deploy-testnet (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
This commit is contained in:
@@ -4,17 +4,18 @@ After=network.target postgresql.service
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
WorkingDirectory=/opt/aitbc/apps/edge-api
|
WorkingDirectory=/opt/aitbc/apps/aitbc-edge
|
||||||
Environment="PATH=/opt/aitbc/venv/bin"
|
Environment="PATH=/opt/aitbc/venv/bin"
|
||||||
Environment="PYTHONPATH=/opt/aitbc/packages/py/aitbc-core/src:/opt/aitbc/apps/edge-api/src:/opt/aitbc"
|
Environment="PYTHONPATH=/opt/aitbc/packages/py/aitbc-core/src:/opt/aitbc/apps/aitbc-edge/src:/opt/aitbc"
|
||||||
Environment="DATABASE_URL=postgresql+asyncpg://aitbc_edge:password@localhost:5432/aitbc_edge"
|
Environment="DATABASE_URL=sqlite+aiosqlite:///opt/aitbc/data/edge.db"
|
||||||
|
Environment="DATA_DIR=/opt/aitbc/data"
|
||||||
Environment="BLOCKCHAIN_RPC_HOST=localhost"
|
Environment="BLOCKCHAIN_RPC_HOST=localhost"
|
||||||
Environment="BLOCKCHAIN_RPC_PORT=8006"
|
Environment="BLOCKCHAIN_RPC_PORT=8006"
|
||||||
Environment="GPU_SERVICE_HOST=localhost"
|
Environment="GPU_SERVICE_HOST=localhost"
|
||||||
Environment="GPU_SERVICE_PORT=8101"
|
Environment="GPU_SERVICE_PORT=8101"
|
||||||
Environment="JWT_SECRET_KEY=CQNLjrtnUVGzdO1skuLsxoiPEEmav2Vj3aA302cvo8I"
|
Environment="JWT_SECRET_KEY=CQNLjrtnUVGzdO1skuLsxoiPEEmav2Vj3aA302cvo8I"
|
||||||
Environment="API_PORT=8103"
|
Environment="API_PORT=8103"
|
||||||
ExecStart=/opt/aitbc/venv/bin/python -m edge_api.main
|
ExecStart=/opt/aitbc/venv/bin/python -m aitbc_edge.main
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=10
|
RestartSec=10
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
"""Island-related schemas for Edge API Service"""
|
"""Island-related schemas for Edge API Service"""
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from sqlalchemy import JSON, Column, Enum as SQLEnum
|
from sqlalchemy import JSON, Column, Enum as SQLEnum, String
|
||||||
from sqlmodel import Field, SQLModel
|
from sqlmodel import Field, SQLModel
|
||||||
|
|
||||||
|
|
||||||
@@ -18,37 +18,37 @@ class IslandStatus(StrEnum):
|
|||||||
|
|
||||||
class IslandMembership(SQLModel, table=True):
|
class IslandMembership(SQLModel, table=True):
|
||||||
"""Island membership in edge API database"""
|
"""Island membership in edge API database"""
|
||||||
|
|
||||||
__tablename__ = "island_memberships"
|
__tablename__ = "island_memberships"
|
||||||
__table_args__ = {"extend_existing": True}
|
__table_args__ = {"extend_existing": True}
|
||||||
|
|
||||||
id: str = Field(default_factory=lambda: f"membership_{uuid4().hex[:8]}", primary_key=True)
|
id: str = Field(default_factory=lambda: f"membership_{uuid4().hex[:8]}", primary_key=True)
|
||||||
island_id: str = Field(sa_column=Column(index=True))
|
island_id: str = Field(sa_column=Column(String, index=True))
|
||||||
island_name: str
|
island_name: str = Field(sa_column=Column(String))
|
||||||
chain_id: str = Field(sa_column=Column(index=True))
|
chain_id: str = Field(sa_column=Column(String, index=True))
|
||||||
status: IslandStatus = Field(
|
status: IslandStatus = Field(
|
||||||
default=IslandStatus.ACTIVE,
|
default=IslandStatus.ACTIVE,
|
||||||
sa_column=Column(SQLEnum(IslandStatus, values_only=True), index=True)
|
sa_column=Column(SQLEnum(IslandStatus, values_only=True), index=True)
|
||||||
)
|
)
|
||||||
role: str = Field(default="compute-provider") # compute-provider, consumer, hub
|
role: str = Field(default="compute-provider", sa_column=Column(String)) # compute-provider, consumer, hub
|
||||||
joined_at: datetime = Field(default_factory=lambda: datetime.utcnow())
|
joined_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||||
peer_count: int = Field(default=0)
|
peer_count: int = Field(default=0)
|
||||||
|
|
||||||
# Additional metadata
|
# Additional metadata
|
||||||
extra_data: dict = Field(default_factory=dict, sa_column=Column(JSON, nullable=True))
|
extra_data: dict = Field(default_factory=dict, sa_column=Column(JSON, nullable=True))
|
||||||
|
|
||||||
|
|
||||||
class BridgeRequest(SQLModel, table=True):
|
class BridgeRequest(SQLModel, table=True):
|
||||||
"""Bridge request for island connectivity"""
|
"""Bridge request for island connectivity"""
|
||||||
|
|
||||||
__tablename__ = "bridge_requests"
|
__tablename__ = "bridge_requests"
|
||||||
__table_args__ = {"extend_existing": True}
|
__table_args__ = {"extend_existing": True}
|
||||||
|
|
||||||
id: str = Field(default_factory=lambda: f"bridge_req_{uuid4().hex[:8]}", primary_key=True)
|
id: str = Field(default_factory=lambda: f"bridge_req_{uuid4().hex[:8]}", primary_key=True)
|
||||||
request_id: str = Field(index=True)
|
request_id: str = Field(sa_column=Column(String, index=True))
|
||||||
source_island_id: str
|
source_island_id: str = Field(sa_column=Column(String))
|
||||||
target_island_id: str
|
target_island_id: str = Field(sa_column=Column(String))
|
||||||
source_node_id: str
|
source_node_id: str = Field(sa_column=Column(String))
|
||||||
status: str = Field(default="pending", index=True) # pending, approved, rejected
|
status: str = Field(default="pending", sa_column=Column(String, index=True)) # pending, approved, rejected
|
||||||
created_at: datetime = Field(default_factory=lambda: datetime.utcnow())
|
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||||
updated_at: datetime = Field(default_factory=lambda: datetime.utcnow())
|
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||||
|
|||||||
@@ -12,7 +12,15 @@ from aitbc import get_logger
|
|||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
# Database URL from environment variable or default
|
# Database URL from environment variable or default
|
||||||
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql+asyncpg://aitbc_edge:password@localhost:5432/aitbc_edge")
|
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite+aiosqlite:///opt/aitbc/data/edge.db")
|
||||||
|
|
||||||
|
# Ensure data directory exists
|
||||||
|
if DATABASE_URL.startswith("sqlite"):
|
||||||
|
db_path = DATABASE_URL.replace("sqlite+aiosqlite:///", "").split("?")[0]
|
||||||
|
db_dir = os.path.dirname(db_path)
|
||||||
|
if db_dir and not os.path.exists(db_dir):
|
||||||
|
os.makedirs(db_dir, exist_ok=True)
|
||||||
|
logger.info(f"Created database directory: {db_dir}")
|
||||||
|
|
||||||
# Create async engine with proper connection pool settings
|
# Create async engine with proper connection pool settings
|
||||||
engine = create_async_engine(
|
engine = create_async_engine(
|
||||||
|
|||||||
@@ -34,20 +34,28 @@ async def submit_job(
|
|||||||
service = JobService(session)
|
service = JobService(session)
|
||||||
job = service.create_job(client_id, req)
|
job = service.create_job(client_id, req)
|
||||||
|
|
||||||
# Create payment if amount is specified
|
# Create payment if amount is specified (optional for proof-of-concept)
|
||||||
if req.payment_amount and req.payment_amount > 0:
|
if req.payment_amount and req.payment_amount > 0:
|
||||||
payment_service = PaymentService(session)
|
try:
|
||||||
payment_create = JobPaymentCreate(
|
payment_service = PaymentService(session)
|
||||||
job_id=job.id,
|
payment_create = JobPaymentCreate(
|
||||||
amount=req.payment_amount,
|
job_id=job.id,
|
||||||
currency=req.payment_currency,
|
amount=req.payment_amount,
|
||||||
payment_method="aitbc_token", # Jobs use AITBC tokens
|
currency=req.payment_currency,
|
||||||
)
|
payment_method="aitbc_token", # Jobs use AITBC tokens
|
||||||
payment = await payment_service.create_payment(job.id, payment_create)
|
)
|
||||||
job.payment_id = payment.id
|
payment = await payment_service.create_payment(job.id, payment_create)
|
||||||
job.payment_status = payment.status
|
job.payment_id = payment.id
|
||||||
session.commit()
|
job.payment_status = payment.status
|
||||||
session.refresh(job)
|
session.commit()
|
||||||
|
session.refresh(job)
|
||||||
|
logger.info(f"Payment created for job {job.id}: {payment.id}")
|
||||||
|
except Exception as e:
|
||||||
|
# Payment creation failure should not block job submission for proof-of-concept
|
||||||
|
logger.warning(f"Payment creation failed for job {job.id}, proceeding without payment: {e}")
|
||||||
|
job.payment_status = "skipped"
|
||||||
|
session.commit()
|
||||||
|
session.refresh(job)
|
||||||
|
|
||||||
return service.to_view(job) # type: ignore[no-any-return]
|
return service.to_view(job) # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user