feat(examples): ✨ Add instance state polling with 5-minute timeout
Enhanced comprehensive example to wait for AppInstance deployment completion: ## New Polling Features: - **State Monitoring**: Polls ShowAppInst every 10 seconds until ready - **Timeout Protection**: 5-minute maximum wait time with context cancellation - **Smart State Detection**: Handles Creating, Ready, Running, Error states - **Progress Feedback**: Real-time status updates during deployment ## Implementation Details: - **waitForInstanceReady()**: Robust polling function with timeout - **State Logic**: Exits on non-creating states (Ready, Running, Error) - **Error Handling**: Distinguishes between polling errors and failure states - **Context Management**: Proper timeout context with cleanup ## User Experience: ``` 5️⃣ Waiting for application instance to be ready... Polling instance state (timeout: 5 minutes)... 📊 Instance state: Creating 📊 Instance state: Creating (power: PowerOn) 📊 Instance state: Ready (power: PowerOn) ✅ Instance reached ready state: Ready ``` This ensures the example demonstrates a complete, realistic deployment workflow where instance creation is fully completed before proceeding to subsequent operations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
cf7fb88aa2
commit
99f3e9f88e
5 changed files with 84 additions and 474 deletions
|
|
@ -9,6 +9,7 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"edp.buildth.ing/DevFW-CICD/edge-connect-client/sdk/client"
|
||||
|
|
@ -46,14 +47,14 @@ func main() {
|
|||
|
||||
// Configuration for the workflow
|
||||
config := WorkflowConfig{
|
||||
Organization: "demo-org",
|
||||
Region: "us-west",
|
||||
AppName: "edge-app-demo",
|
||||
AppVersion: "1.0.0",
|
||||
CloudletOrg: "cloudlet-provider",
|
||||
CloudletName: "demo-cloudlet",
|
||||
InstanceName: "app-instance-1",
|
||||
FlavorName: "m4.small",
|
||||
Organization: "edp2",
|
||||
Region: "EU",
|
||||
AppName: "edge-app-demo",
|
||||
AppVersion: "1.0.0",
|
||||
CloudletOrg: "TelekomOP",
|
||||
CloudletName: "Munich",
|
||||
InstanceName: "app-instance-1",
|
||||
FlavorName: "EU.small",
|
||||
}
|
||||
|
||||
fmt.Printf("🚀 Starting comprehensive EdgeXR workflow demonstration\n")
|
||||
|
|
@ -75,13 +76,13 @@ func main() {
|
|||
// WorkflowConfig holds configuration for the demonstration workflow
|
||||
type WorkflowConfig struct {
|
||||
Organization string
|
||||
Region string
|
||||
AppName string
|
||||
AppVersion string
|
||||
CloudletOrg string
|
||||
Region string
|
||||
AppName string
|
||||
AppVersion string
|
||||
CloudletOrg string
|
||||
CloudletName string
|
||||
InstanceName string
|
||||
FlavorName string
|
||||
FlavorName string
|
||||
}
|
||||
|
||||
func runComprehensiveWorkflow(ctx context.Context, c *client.Client, config WorkflowConfig) error {
|
||||
|
|
@ -97,10 +98,12 @@ func runComprehensiveWorkflow(ctx context.Context, c *client.Client, config Work
|
|||
Name: config.AppName,
|
||||
Version: config.AppVersion,
|
||||
},
|
||||
Deployment: "kubernetes",
|
||||
ImageType: "ImageTypeDocker",
|
||||
ImagePath: "nginx:latest",
|
||||
DefaultFlavor: client.Flavor{Name: config.FlavorName},
|
||||
Deployment: "kubernetes",
|
||||
ImageType: "ImageTypeDocker",
|
||||
ImagePath: "https://registry-1.docker.io/library/nginx:latest",
|
||||
DefaultFlavor: client.Flavor{Name: config.FlavorName},
|
||||
ServerlessConfig: struct{}{},
|
||||
AllowServerless: true,
|
||||
RequiredOutboundConnections: []client.SecurityRule{
|
||||
{
|
||||
Protocol: "tcp",
|
||||
|
|
@ -179,8 +182,8 @@ func runComprehensiveWorkflow(ctx context.Context, c *client.Client, config Work
|
|||
fmt.Printf("✅ App instance created: %s on cloudlet %s/%s\n",
|
||||
config.InstanceName, config.CloudletOrg, config.CloudletName)
|
||||
|
||||
// 5. Show Application Instance Details
|
||||
fmt.Println("\n5️⃣ Querying application instance details...")
|
||||
// 5. Wait for Application Instance to be Ready
|
||||
fmt.Println("\n5️⃣ Waiting for application instance to be ready...")
|
||||
instanceKey := client.AppInstanceKey{
|
||||
Organization: config.Organization,
|
||||
Name: config.InstanceName,
|
||||
|
|
@ -190,11 +193,11 @@ func runComprehensiveWorkflow(ctx context.Context, c *client.Client, config Work
|
|||
},
|
||||
}
|
||||
|
||||
instanceDetails, err := c.ShowAppInstance(ctx, instanceKey, config.Region)
|
||||
instanceDetails, err := waitForInstanceReady(ctx, c, instanceKey, config.Region, 5*time.Minute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to show app instance: %w", err)
|
||||
return fmt.Errorf("failed to wait for instance ready: %w", err)
|
||||
}
|
||||
fmt.Printf("✅ Instance details retrieved:\n")
|
||||
fmt.Printf("✅ Instance is ready:\n")
|
||||
fmt.Printf(" • Name: %s\n", instanceDetails.Key.Name)
|
||||
fmt.Printf(" • App: %s/%s v%s\n", instanceDetails.AppKey.Organization, instanceDetails.AppKey.Name, instanceDetails.AppKey.Version)
|
||||
fmt.Printf(" • Cloudlet: %s/%s\n", instanceDetails.Key.CloudletKey.Organization, instanceDetails.Key.CloudletKey.Name)
|
||||
|
|
@ -300,4 +303,51 @@ func getEnvOrDefault(key, defaultValue string) string {
|
|||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
// waitForInstanceReady polls the instance status until it's no longer "Creating" or timeout
|
||||
func waitForInstanceReady(ctx context.Context, c *client.Client, instanceKey client.AppInstanceKey, region string, timeout time.Duration) (client.AppInstance, error) {
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
ticker := time.NewTicker(10 * time.Second) // Poll every 10 seconds
|
||||
defer ticker.Stop()
|
||||
|
||||
fmt.Printf(" Polling instance state (timeout: %.0f minutes)...\n", timeout.Minutes())
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-timeoutCtx.Done():
|
||||
return client.AppInstance{}, fmt.Errorf("timeout waiting for instance to be ready after %v", timeout)
|
||||
|
||||
case <-ticker.C:
|
||||
instance, err := c.ShowAppInstance(timeoutCtx, instanceKey, region)
|
||||
if err != nil {
|
||||
// Log error but continue polling
|
||||
fmt.Printf(" ⚠️ Error checking instance state: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf(" 📊 Instance state: %s", instance.State)
|
||||
if instance.PowerState != "" {
|
||||
fmt.Printf(" (power: %s)", instance.PowerState)
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
// Check if instance is ready (not in creating state)
|
||||
state := strings.ToLower(instance.State)
|
||||
if state != "" && state != "creating" && state != "create requested" {
|
||||
if state == "ready" || state == "running" {
|
||||
fmt.Printf(" ✅ Instance reached ready state: %s\n", instance.State)
|
||||
return instance, nil
|
||||
} else if state == "error" || state == "failed" || strings.Contains(state, "error") {
|
||||
return instance, fmt.Errorf("instance entered error state: %s", instance.State)
|
||||
} else {
|
||||
// Instance is in some other stable state (not creating)
|
||||
fmt.Printf(" ✅ Instance reached stable state: %s\n", instance.State)
|
||||
return instance, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue