feat(vm): hoàn tiền khi cấp VM lỗi, theo dõi job queue, uuid dịch vụ cho ticket, chuẩn hoá RAM addon

- VmProvisionException/VmProvisionRefund xử lý lỗi cấp phát VM
- QueueJobInspector + QueueMonitorController xem chi tiết job
- Thêm service uuid cho ticket, thời lượng cho activity_logs
- Migration chuẩn hoá RAM addon sang MB, trạng thái deleting cho snapshot

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-30 11:54:05 +07:00
co-authored by Claude Sonnet 5.5
parent 7136bec265
commit 62596d9063
32 changed files with 514 additions and 107 deletions
@@ -6,13 +6,17 @@ namespace App\Jobs\VirtualMachine\Create;
use App\Http\Services\vCenter;
use App\Jobs\VirtualMachine\Provision\UpdateVmConfigJob;
use App\Exceptions\VmProvisionException;
use App\Models\OrderItem;
use App\Models\Service;
use App\Models\VmProvisionLock;
use App\Services\ActivityLogger;
use App\Services\VirtualMachine\VmAddonResolver;
use App\Services\VirtualMachine\VmInfrastructureResolver;
use App\Services\VirtualMachine\VmIpReservationService;
use App\Services\VirtualMachine\VmModuleService;
use App\Services\VirtualMachine\VmNotificationService;
use App\Services\VirtualMachine\VmProvisionRefund;
use App\Services\VirtualMachine\VmProvisionLogger;
use App\Services\VirtualMachine\VmServiceSyncService;
use App\Services\VirtualMachine\VmVcenterErrorTranslator;
@@ -51,6 +55,7 @@ class CreateVirtualMachineJob implements ShouldQueue
VmNotificationService $notification,
VmVcenterErrorTranslator $errorTranslator,
VmIpReservationService $ipReservation,
VmProvisionRefund $refund,
): bool {
$reservation = null;
$ipPoolId = null;
@@ -141,8 +146,9 @@ class CreateVirtualMachineJob implements ShouldQueue
]);
if (is_array($result) && ($result['error'] ?? false)) {
throw new RuntimeException(
$errorTranslator->translate($result, $this->item->server_name)
throw new VmProvisionException(
$errorTranslator->translate($result, $this->item->server_name),
$errorTranslator->detail($result),
);
}
@@ -161,7 +167,11 @@ class CreateVirtualMachineJob implements ShouldQueue
'vm_id' => $vmId,
]);
$moduleVmware = $moduleService->create($this->item, $infra, $vmId);
$moduleVmware = $moduleService->create($this->item, $infra, $vmId, [
'cpu' => (int) $product->cpu + $addonData['cpu'],
'ram_mb' => ((int) $product->ram + $addonData['ram']) * 1024,
'disk_gb' => (int) $product->disk + $addonData['disk'],
]);
$vmLogger->success('ModuleVmware created', [
'module_vmware_id' => $moduleVmware->id,
@@ -210,14 +220,31 @@ class CreateVirtualMachineJob implements ShouldQueue
}
$lock?->update(['status' => 'failed']);
Service::where('order_item_id', $this->item->id)
->whereIn('status', ['pending', 'provisioning'])
->update(['status' => 'failed']);
$adminDetail = $e instanceof VmProvisionException ? $e->adminDetail : $e->getMessage();
$vmLogger->exception('Create VM job failed', $e, [
'order_item_id' => $this->item->id,
'is_retry' => $this->isRetry,
'admin_detail' => $adminDetail,
]);
$failedService = Service::where('order_item_id', $this->item->id)->first();
if ($failedService) {
app(ActivityLogger::class)->log(
'provision_failed',
'service',
'Khởi tạo máy ảo thất bại — ' . $adminDetail,
$failedService,
);
}
if (!$this->isRetry) {
$notification->failed($this->item, $e->getMessage());
$refunded = $refund->refund($this->item, $e->getMessage());
$notification->failed($this->item, $e->getMessage() . ($refunded ? ' (đã tự động hoàn tiền cho khách)' : ''));
}
return false;