Task Handling - FreshPerf/PVE4J GitHub Wiki
Proxmox operations often involve long-running tasks. This guide explains how to work with tasks in PVE4J.
When you perform operations like starting a VM, cloning, or resizing disks, Proxmox creates a task that runs asynchronously. Each task has:
-
UPID - Unique Process ID (e.g.,
UPID:node:00000001:00000001:00000001:qmstart:100:root@pam:) - Node - The node where the task runs
- Status - Current task status (running, stopped)
- Exit Status - Result code (OK, or error message)
Operations that create tasks return a PveTask object:
import fr.freshperf.pve4j.entities.PveTask;
PveTask task = proxmox.getNodes()
.get("pve-node-01")
.getQemu()
.get(100)
.start()
.execute();
System.out.println("Task UPID: " + task.getUpid());
System.out.println("Node: " + task.getNode());import fr.freshperf.pve4j.entities.PveTaskStatus;
try {
PveTask task = vm.start().execute();
PveTaskStatus status = proxmox.getTaskStatus(task).execute();
System.out.println("Status: " + status.getStatus());
System.out.println("Exit Status: " + status.getExitstatus());
System.out.println("Type: " + status.getType());
System.out.println("User: " + status.getUser());
System.out.println("Start Time: " + status.getStarttime());
} catch (ProxmoxAPIError | InterruptedException e) {
e.printStackTrace();
}PveTaskStatus status = proxmox.getTaskStatus(task).execute();
if (status.isSuccessful()) {
System.out.println("Task completed successfully!");
} else if (status.isCompleted()) {
System.err.println("Task failed: " + status.getExitstatus());
} else {
System.out.println("Task is still running...");
}PveTaskStatus status = proxmox.getTaskStatus("pve-node-01", upid).execute();The simplest way to wait for a task to complete:
try {
PveTask task = proxmox.getNodes()
.get("pve-node-01")
.getQemu()
.get(100)
.start()
.waitForCompletion(proxmox)
.execute();
System.out.println("VM started successfully!");
} catch (ProxmoxAPIError | InterruptedException e) {
System.err.println("Failed to start VM: " + e.getMessage());
}By default, waitForCompletion() polls every second. You can customize this with taskCheckDelay():
import java.time.Duration;
// Using milliseconds
PveTask task = proxmox.getNodes()
.get("pve-node-01")
.getQemu()
.get(100)
.start()
.waitForCompletion(proxmox)
.taskCheckDelay(5000) // Poll every 5 seconds
.execute();
// Using Duration for better readability
PveTask task = proxmox.getNodes()
.get("pve-node-01")
.getQemu()
.get(100)
.cloneVm(200)
.waitForCompletion(proxmox)
.taskCheckDelay(Duration.ofSeconds(10)) // Long operations can use longer intervals
.execute();Set a maximum time to wait for task completion:
PveTask task = proxmox.getNodes()
.get("pve-node-01")
.getQemu()
.get(100)
.cloneVm(200)
.waitForCompletion(proxmox)
.taskTimeout(Duration.ofMinutes(10))
.taskCheckDelay(Duration.ofSeconds(2))
.execute();You can also wait for task completion after execution using the static helper:
import fr.freshperf.pve4j.request.ProxmoxRequest;
// Fire and forget, then wait later
PveTask task = vm.start().execute();
// Do other work...
// Wait for completion with default 1 second polling
ProxmoxRequest.waitForCompletion(proxmox, task);
// Or specify custom polling interval
ProxmoxRequest.waitForCompletion(proxmox, task, 5000); // 5 second polling
// Or with Duration and timeout
ProxmoxRequest.waitForCompletion(proxmox, task, Duration.ofSeconds(2), Duration.ofMinutes(5));For complete control over the polling logic:
PveTask task = vm.start().execute();
boolean completed = false;
while (!completed) {
Thread.sleep(5000); // Poll every 5 seconds
PveTaskStatus status = proxmox.getTaskStatus(task).execute();
if (status.isCompleted()) {
completed = true;
if (status.isSuccessful()) {
System.out.println("Task completed successfully!");
} else {
System.err.println("Task failed: " + status.getExitstatus());
}
}
}For non-blocking operations, use onCompletion():
try {
proxmox.getNodes()
.get("pve-node-01")
.getQemu()
.get(100)
.start()
.onCompletion((task, status) -> {
if (status.isSuccessful()) {
System.out.println("VM started successfully!");
} else {
System.err.println("VM start failed: " + status.getExitstatus());
}
}, proxmox)
.execute();
System.out.println("Start task submitted, continuing with other work...");
// Your code continues here while the task runs in the background
} catch (ProxmoxAPIError | InterruptedException e) {
e.printStackTrace();
}Submit a task without waiting:
PveTask task = vm.start().execute();
System.out.println("Task submitted: " + task.getUpid());
// Continue immediatelyUse Case: When you don't need to know when the task completes.
Wait for task to complete before continuing:
PveTask task = vm.start()
.waitForCompletion(proxmox)
.execute();
System.out.println("VM is now running");
// Task is guaranteed to be completeUse Case: When you need the task to complete before proceeding.
Submit task and handle completion asynchronously:
vm.start()
.onCompletion((task, status) -> {
System.out.println("Task completed!");
}, proxmox)
.execute();
System.out.println("Task running in background");
// Continue with other workUse Case: When you want to perform other work while task runs.
import java.util.concurrent.*;
ExecutorService executor = Executors.newFixedThreadPool(5);
List<Integer> vmids = Arrays.asList(100, 101, 102, 103, 104);
List<CompletableFuture<Void>> futures = vmids.stream()
.map(vmid -> CompletableFuture.runAsync(() -> {
try {
proxmox.getNodes()
.get("pve-node-01")
.getQemu()
.get(vmid)
.start()
.waitForCompletion(proxmox)
.execute();
System.out.println("VM " + vmid + " started");
} catch (Exception e) {
System.err.println("Failed to start VM " + vmid + ": " + e.getMessage());
}
}, executor))
.collect(Collectors.toList());
// Wait for all VMs to start
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
executor.shutdown();Use Case: Starting multiple VMs in parallel.
try {
PveTask task = vm.start()
.waitForCompletion(proxmox)
.execute();
// Check final status
PveTaskStatus status = proxmox.getTaskStatus(task).execute();
if (!status.isSuccessful()) {
System.err.println("Task failed with exit status: " + status.getExitstatus());
}
} catch (ProxmoxAPIError e) {
System.err.println("API Error: " + e.getMessage());
System.err.println("Status Code: " + e.getStatusCode());
System.err.println("Response: " + e.getResponseBody());
} catch (InterruptedException e) {
System.err.println("Operation interrupted");
Thread.currentThread().interrupt();
}import java.util.concurrent.*;
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<PveTask> future = executor.submit(() -> {
return vm.start()
.waitForCompletion(proxmox)
.execute();
});
try {
PveTask task = future.get(30, TimeUnit.SECONDS);
System.out.println("VM started within timeout");
} catch (TimeoutException e) {
System.err.println("Operation timed out after 30 seconds");
future.cancel(true);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
} finally {
executor.shutdown();
}PveTask task = vm.cloneVm(200).execute();
System.out.println("Monitoring clone task...");
boolean running = true;
while (running) {
Thread.sleep(2000);
PveTaskStatus status = proxmox.getTaskStatus(task).execute();
System.out.println("Status: " + status.getStatus());
if (status.isCompleted()) {
running = false;
if (status.isSuccessful()) {
System.out.println("Clone completed successfully!");
} else {
System.err.println("Clone failed: " + status.getExitstatus());
}
}
}| Task Type | Description |
|---|---|
qmstart |
Start QEMU VM |
qmstop |
Stop QEMU VM |
qmshutdown |
Shutdown QEMU VM |
qmreboot |
Reboot QEMU VM |
qmclone |
Clone QEMU VM |
qmresize |
Resize QEMU disk |
qmdestroy |
Delete QEMU VM |
qmconfig |
Update QEMU configuration |
vzcreate |
Create LXC container |
vzstart |
Start LXC container |
vzstop |
Stop LXC container |
vzdump |
Backup operation |
- VM Management - VM lifecycle operations
- Error Handling - Comprehensive error handling
- Container Management - LXC container tasks