package main

import (
	"context"
	"fmt"
	"time"
)

// section: main
func main() {
	// Create a context with cancellation
	ctx, cancel := context.WithCancel(context.Background())

	// Simulate a request that gets canceled
	go func() {
		time.Sleep(100 * time.Millisecond)
		fmt.Println("Request canceled by client")
		cancel()
	}()

	// Simulate processing a request
	processRequest(ctx)
}

// section: process
func processRequest(ctx context.Context) {
	// Start some work
	fmt.Println("Processing request...")

	// Wait for cancellation
	<-ctx.Done()
	fmt.Printf("Request context canceled: %v\n", ctx.Err())

	// We still need to log metrics even after cancellation
	// Using ctx directly would fail because it's already canceled
	logMetrics(ctx)
}

// section: log-metrics
func logMetrics(ctx context.Context) {
	// Create a context that won't be canceled when parent is canceled
	// This allows us to complete logging even after request cancellation
	cleanupCtx := context.WithoutCancel(ctx)

	// Add a timeout to the cleanup context to prevent indefinite hangs
	cleanupCtx, cancel := context.WithTimeout(cleanupCtx, 5*time.Second)
	defer cancel()

	// Simulate sending metrics to a remote service
	fmt.Println("Logging metrics with WithoutCancel context...")

	select {
	case <-time.After(50 * time.Millisecond):
		fmt.Println("Metrics logged successfully")
	case <-cleanupCtx.Done():
		fmt.Printf("Metrics logging failed: %v\n", cleanupCtx.Err())
	}
}

// section: output
/*
Processing request...
Request canceled by client
Request context canceled: context canceled
Logging metrics with WithoutCancel context...
Metrics logged successfully
*/
