Refactor subscription synchronization logic for improved handling

- Enhanced the subscription syncing process to prioritize concrete subscription UUIDs for updates and creations, ensuring idempotency.
- Implemented atomic updates for existing subscriptions and streamlined the creation of new subscriptions when a UUID is available.
- Improved logging for subscription updates and creations to provide clearer feedback on sync actions.
- Added handling for cases where no subscription UUID is present, avoiding unnecessary record creation.
This commit is contained in:
machka-pasla
2025-08-07 23:47:19 +03:00
parent bb7641bb74
commit 149ff057a9
+76 -36
View File
@@ -122,48 +122,88 @@ async def perform_sync(panel_service: PanelApiService, session: AsyncSession,
panel_expire_at_iso.replace("Z", "+00:00") panel_expire_at_iso.replace("Z", "+00:00")
) )
# Update or create subscription # Prefer syncing by concrete subscription UUID (shortUuid/subscriptionUuid)
active_sub = await subscription_dal.get_active_subscription_by_user_id( subscription_uuid_from_panel = (
session, actual_user_id, panel_uuid panel_user_dict.get("subscriptionUuid")
or panel_user_dict.get("shortUuid")
) )
if active_sub: if subscription_uuid_from_panel:
# Check if subscription needs update # Try to find subscription by its panel_subscription_uuid first (idempotent)
if (active_sub.end_date != panel_expire_at or existing_sub_by_uuid = (
active_sub.status_from_panel != panel_status or await subscription_dal.get_subscription_by_panel_subscription_uuid(
active_sub.is_active != (panel_status == "ACTIVE")): session, subscription_uuid_from_panel
)
await subscription_dal.update_subscription_end_date( )
session, active_sub.subscription_id, panel_expire_at
if existing_sub_by_uuid:
# Atomic update of all relevant fields
await subscription_dal.update_subscription(
session,
existing_sub_by_uuid.subscription_id,
{
"user_id": actual_user_id,
"panel_user_uuid": panel_uuid,
"end_date": panel_expire_at,
"is_active": panel_status == "ACTIVE",
"status_from_panel": panel_status,
},
) )
# Update status fields
active_sub.status_from_panel = panel_status
active_sub.is_active = (panel_status == "ACTIVE")
subscriptions_synced_count += 1 subscriptions_synced_count += 1
subscriptions_updated += 1 subscriptions_updated += 1
user_was_updated = True user_was_updated = True
logging.info(f"Updated subscription for user {actual_user_id}: expires {panel_expire_at}, status {panel_status}") logging.info(
f"Synced existing subscription {existing_sub_by_uuid.subscription_id} for user {actual_user_id}: expires {panel_expire_at}, status {panel_status}"
)
else:
# Create a new subscription only when we have a concrete subscription UUID
sub_payload = {
"user_id": actual_user_id,
"panel_user_uuid": panel_uuid,
"panel_subscription_uuid": subscription_uuid_from_panel,
# Do not guess precise start_date from panel; keep nullable
"start_date": None,
"end_date": panel_expire_at,
"duration_months": None,
"is_active": panel_status == "ACTIVE",
"status_from_panel": panel_status,
"traffic_limit_bytes": settings.user_traffic_limit_bytes,
}
created_sub = await subscription_dal.upsert_subscription(
session, sub_payload
)
subscriptions_synced_count += 1
subscriptions_created += 1
user_was_updated = True
logging.info(
f"Created subscription {created_sub.subscription_id} for user {actual_user_id} by panel_sub_uuid {subscription_uuid_from_panel}"
)
else: else:
# Create new subscription record # No subscription UUID from panel: only update an already active subscription for this user/panel UUID
subscription_uuid_to_use = panel_subscription_uuid or panel_uuid active_sub = await subscription_dal.get_active_subscription_by_user_id(
session, actual_user_id, panel_uuid
logging.info(f"Creating new subscription for user {actual_user_id} with UUID {subscription_uuid_to_use}") )
if active_sub:
sub_payload = { await subscription_dal.update_subscription(
"user_id": actual_user_id, session,
"panel_user_uuid": panel_uuid, active_sub.subscription_id,
"panel_subscription_uuid": subscription_uuid_to_use, {
"start_date": datetime.now(timezone.utc), "end_date": panel_expire_at,
"end_date": panel_expire_at, "is_active": panel_status == "ACTIVE",
"duration_months": 1, # Default "status_from_panel": panel_status,
"is_active": panel_status == "ACTIVE", },
"status_from_panel": panel_status, )
"traffic_limit_bytes": settings.user_traffic_limit_bytes, subscriptions_synced_count += 1
} subscriptions_updated += 1
await subscription_dal.upsert_subscription(session, sub_payload) user_was_updated = True
subscriptions_synced_count += 1 logging.info(
subscriptions_created += 1 f"Updated active subscription {active_sub.subscription_id} for user {actual_user_id}: expires {panel_expire_at}, status {panel_status}"
user_was_updated = True )
else:
# Without a concrete subscription UUID we avoid creating new records to keep sync idempotent
logging.debug(
f"No subscriptionUuid for panel user {panel_uuid}; skipped creation for user {actual_user_id}"
)
except Exception as e: except Exception as e:
sync_errors.append(f"Error syncing subscription for user {actual_user_id}: {str(e)}") sync_errors.append(f"Error syncing subscription for user {actual_user_id}: {str(e)}")