yao/agent/context/RESOURCE_MANAGEMENT.md
Max 8dedd93a90 Remove deprecated agent_test.go and mcp package files; refactor context and trace handling for improved functionality.
- Deleted agent_test.go to streamline testing structure.
- Removed mcp package and its related fetch and search files to simplify the codebase.
- Enhanced context handling in jsapi_test.go and jsapi.go for better integration with JavaScript.
- Introduced no-op objects for Trace and Node to handle uninitialized states gracefully.
- Updated i18n translations to include new MCP-related labels and descriptions.
2025-11-28 19:26:33 +08:00

5.9 KiB

Context Resource Management

This document explains the resource management strategy for Context and Trace objects in JavaScript.

Overview

Both Context and Trace objects provide two cleanup methods:

  • __release() - Internal method called automatically by:

    • V8 garbage collector (when object is collected)
    • Use() function (immediate cleanup after callback)
  • Release() - Public method for explicit manual cleanup:

    • Called in try-finally blocks
    • Provides immediate resource cleanup
    • Same implementation as __release() - they do the same thing

Resource Hierarchy

When Context.Release() is called, it automatically releases:

  1. Trace object - If present, calls Trace.__release() to cleanup:

    • Go bridge registry entries
    • Trace manager resources
    • Background goroutines
  2. Context object - Releases:

    • Go bridge registry entry for the Context itself

This ensures proper cleanup of the entire resource tree.

Usage Patterns

Best for: Most cases, clean code, automatic resource management

// Context is released automatically after callback
Use(Context, contextData, (ctx) => {
  // Access Trace (released automatically with context)
  const trace = ctx.Trace
  const node = trace.Add({ type: "step" }, { label: "Processing" })
  
  trace.Info("Doing work")
  node.Complete({ result: "done" })
  
  return result
})
// ctx.Release() called automatically, which also releases Trace

Pattern 2: Manual Cleanup with try-finally

Best for: Explicit control, critical memory scenarios

const ctx = getContext() // or passed as parameter
const trace = ctx.Trace

try {
  const node = trace.Add({ type: "step" }, { label: "Processing" })
  
  trace.Info("Doing work")
  node.Complete({ result: "done" })
  
  return result
} finally {
  // Explicit cleanup (also releases Trace)
  ctx.Release()
}

Pattern 3: Separate Trace Cleanup

Best for: When you want to release Trace independently

const ctx = getContext()
const trace = ctx.Trace

try {
  const node = trace.Add({ type: "step" }, { label: "Processing" })
  trace.Info("Doing work")
  node.Complete({ result: "done" })
  
  // Release trace early if needed
  trace.Release()
  
  // Continue using ctx...
  return result
} finally {
  // Release context (Trace already released, safe to call again)
  ctx.Release()
}

Avoid in production: Relies on GC, unpredictable timing

function processData(ctx) {
  const trace = ctx.Trace
  const node = trace.Add({ type: "step" }, { label: "Processing" })
  
  trace.Info("Doing work")
  node.Complete({ result: "done" })
  
  return result
  // Waits for V8 GC to call __release() - SLOW!
}

No-op Trace Handling

When Trace is not initialized, ctx.Trace returns a no-op object:

  • All methods are no-ops (do nothing)
  • Release() is safe to call (no-op)
  • No errors are thrown
  • Provides consistent API regardless of trace initialization
// Works even if Trace is not initialized
const ctx = getContext()
const trace = ctx.Trace // might be no-op

trace.Info("Message") // safe even if no-op
trace.Release()       // safe even if no-op
ctx.Release()         // always safe

Error Handling

Cleanup happens even when errors occur:

const ctx = getContext()
try {
  const trace = ctx.Trace
  const node = trace.Add({ type: "step" }, { label: "Processing" })
  
  throw new Error("Something went wrong")
  
} finally {
  // Cleanup still happens
  ctx.Release() // also releases Trace
}

With Use():

try {
  Use(Context, contextData, (ctx) => {
    throw new Error("Something went wrong")
  })
} catch (error) {
  // Error is caught
  // ctx.Release() was already called automatically
}

Memory Management

✅ Good: Immediate Cleanup

// Loop with immediate cleanup
for (let i = 0; i < 10000; i++) {
  Use(Context, data, (ctx) => {
    const trace = ctx.Trace
    trace.Info(`Processing item ${i}`)
    // Released immediately after each iteration
  })
}

❌ Bad: Waiting for GC

// Memory accumulates until GC runs
for (let i = 0; i < 10000; i++) {
  const ctx = getContext()
  const trace = ctx.Trace
  trace.Info(`Processing item ${i}`)
  // No cleanup - may run out of memory!
}

Implementation Details

Context.Release() / Context.__release()

  1. Checks if ctx.Trace exists
  2. If yes, calls trace.__release() to cleanup Trace resources
  3. Releases Context from bridge registry
  4. Safe to call multiple times (idempotent)
  5. Errors in cleanup are silently ignored

Trace.Release() / Trace.__release()

  1. Releases Go manager object from bridge registry
  2. Calls trace.Release(traceID) to cleanup:
    • Remove from global trace registry
    • Stop background goroutines
    • Free associated resources
  3. Safe to call multiple times (idempotent)

No-op Objects

Both no-op Trace and no-op Node provide:

  • All methods as no-ops
  • Release() and __release() methods
  • Consistent API for error-free operation
  • Zero memory overhead

Best Practices

  1. ✅ Use Use() for automatic cleanup in most cases
  2. ✅ Use try-finally with Release() when you need explicit control
  3. ✅ Release Context (which also releases Trace) rather than releasing each separately
  4. ✅ Release resources in loops to prevent memory accumulation
  5. ❌ Don't rely on GC for resource cleanup in production code
  6. ❌ Don't worry about calling Release() twice - it's idempotent

Testing

See jsapi_release_test.go for comprehensive tests of:

  • Context Release
  • Trace Release
  • Cascading cleanup (Context → Trace)
  • try-finally pattern
  • No-op object Release
  • Error handling with cleanup

Run tests:

cd yao
go test -v ./agent/context -run Release