or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

architecture.mdasync-tasks.mddata-processing.mdfile-system.mdindex.mdlogging.mdprocess-execution.md
tile.json

async-tasks.mddocs/

Async Task Management

Concurrent task execution with cancellation support, promise utilities, and error aggregation for managing complex asynchronous workflows. Provides utilities for task coordination, error handling, and promise-based operations.

Capabilities

Async Task Manager

Manages concurrent execution of multiple asynchronous tasks with cancellation support.

/**
 * Manages concurrent asynchronous tasks with cancellation support
 */
class AsyncTaskManager {
  /** Array of managed task promises */
  readonly tasks: Array<Promise<any>>;
  
  /** Array of accumulated errors from failed tasks */
  private readonly errors: Array<Error>;
  
  /**
   * Create task manager with cancellation token
   * @param cancellationToken - Token for task cancellation
   */
  constructor(cancellationToken: CancellationToken);
  
  /**
   * Add a task function to be executed
   * @param task - Function returning a promise
   */
  add(task: () => Promise<any>): void;
  
  /**
   * Add an already-created promise to be managed
   * @param promise - Promise to manage
   */
  addTask(promise: Promise<any>): void;
  
  /**
   * Cancel all managed tasks
   */
  cancelTasks(): void;
  
  /**
   * Wait for all tasks to complete and return results
   * @returns Promise resolving to array of task results
   * @throws NestedError if any tasks failed
   */
  awaitTasks(): Promise<Array<any>>;
}

Usage Examples:

import { AsyncTaskManager } from "builder-util";

// Create task manager
const cancellationToken = new CancellationToken();
const taskManager = new AsyncTaskManager(cancellationToken);

// Add task functions
taskManager.add(async () => {
  return await compileTypeScript();
});

taskManager.add(async () => {
  return await bundleAssets();
});

taskManager.add(async () => {
  return await optimizeImages();
});

// Add existing promises
const existingTask = processData();
taskManager.addTask(existingTask);

try {
  // Wait for all tasks to complete
  const results = await taskManager.awaitTasks();
  console.log("All tasks completed:", results);
} catch (error) {
  console.error("Some tasks failed:", error);
  
  // Cancel remaining tasks if needed
  taskManager.cancelTasks();
}

Promise Utilities

Utility functions for enhanced promise handling and error management.

/**
 * Execute a promise with a guaranteed finally block
 * @param promise - Promise to execute
 * @param task - Function to run in finally block, receives error status
 * @returns Promise resolving to the original promise result
 */
function executeFinally<T>(
  promise: Promise<T>, 
  task: (isErrorOccurred: boolean) => Promise<any>
): Promise<T>;

/**
 * Return null if promise fails due to file not existing
 * @param promise - Promise that might fail with ENOENT
 * @returns Promise resolving to result or null if file doesn't exist
 */
function orNullIfFileNotExist<T>(promise: Promise<T>): Promise<T | null>;

/**
 * Return fallback value if promise fails due to file not existing
 * @param promise - Promise that might fail with ENOENT
 * @param fallbackValue - Value to return if file doesn't exist
 * @returns Promise resolving to result or fallback value
 */
function orIfFileNotExist<T>(promise: Promise<T>, fallbackValue: T): Promise<T>;

Usage Examples:

import { executeFinally, orNullIfFileNotExist, orIfFileNotExist } from "builder-util";

// Execute with guaranteed cleanup
const result = await executeFinally(
  processLargeFile("/path/to/file.dat"),
  async (isErrorOccurred) => {
    // Cleanup always runs, regardless of success/failure
    await cleanupTempFiles();
    
    if (isErrorOccurred) {
      console.log("Processing failed, cleanup completed");
    } else {
      console.log("Processing succeeded, cleanup completed");
    }
  }
);

// Handle optional file operations
const config = await orNullIfFileNotExist(
  readFile("/optional/config.json")
);

if (config) {
  console.log("Config loaded:", config);
} else {
  console.log("No config file found, using defaults");
}

// Handle with fallback value
const settings = await orIfFileNotExist(
  readSettingsFile("/user/settings.json"),
  getDefaultSettings()
);

Error Aggregation

Specialized error class for handling multiple related errors.

/**
 * Error class that aggregates multiple errors into a single error
 */
class NestedError extends Error {
  /**
   * Create error from array of errors
   * @param errors - Array of errors to aggregate
   * @param message - Optional custom message prefix
   */
  constructor(errors: Array<Error>, message?: string);
}

Usage Examples:

import { NestedError } from "builder-util";

// Collect errors from multiple operations
const errors: Array<Error> = [];

try {
  await operation1();
} catch (error) {
  errors.push(error);
}

try {
  await operation2();
} catch (error) {
  errors.push(error);
}

try {
  await operation3();
} catch (error) {
  errors.push(error);
}

// Throw aggregated error if any failed
if (errors.length > 0) {
  throw new NestedError(errors, "Multiple operations failed:");
}

Process Error Handling

Utility for handling fatal errors and process termination.

/**
 * Print error and exit process with code 1
 * @param error - Error to print before exiting
 */
function printErrorAndExit(error: Error): void;

Usage Examples:

import { printErrorAndExit } from "builder-util";

// Handle fatal errors
process.on("unhandledRejection", (error: Error) => {
  console.error("Unhandled promise rejection:");
  printErrorAndExit(error);
});

// Use in CLI applications
try {
  await runBuildProcess();
} catch (error) {
  printErrorAndExit(error);
}

Usage Patterns

Parallel Build Tasks

import { AsyncTaskManager } from "builder-util";

class BuildPipeline {
  async build(targets: Array<BuildTarget>) {
    const cancellationToken = new CancellationToken();
    const taskManager = new AsyncTaskManager(cancellationToken);
    
    // Add build tasks for each target
    for (const target of targets) {
      taskManager.add(async () => {
        console.log(`Building for ${target.platform}-${target.arch}`);
        return await this.buildForTarget(target);
      });
    }
    
    // Add asset processing in parallel
    taskManager.add(async () => {
      return await this.processAssets();
    });
    
    taskManager.add(async () => {
      return await this.generateManifests();
    });
    
    try {
      const results = await taskManager.awaitTasks();
      console.log("All build tasks completed");
      return results;
    } catch (error) {
      console.error("Build failed:", error);
      taskManager.cancelTasks();
      throw error;
    }
  }
}

Resource Management with Cleanup

import { executeFinally } from "builder-util";

class ResourceManager {
  async processWithResources<T>(operation: () => Promise<T>): Promise<T> {
    const resources = await this.acquireResources();
    
    return executeFinally(
      operation(),
      async (isErrorOccurred) => {
        await this.releaseResources(resources);
        
        if (isErrorOccurred) {
          await this.cleanupFailedOperation();
        }
      }
    );
  }
  
  private async acquireResources() {
    // Acquire database connections, file handles, etc.
    return {
      dbConnection: await connectToDatabase(),
      tempDir: await createTempDirectory()
    };
  }
  
  private async releaseResources(resources: any) {
    // Always cleanup resources
    await resources.dbConnection?.close();
    await removeTempDirectory(resources.tempDir);
  }
}

Graceful File Operations

import { orNullIfFileNotExist, orIfFileNotExist } from "builder-util";

class ConfigManager {
  async loadConfiguration(): Promise<AppConfig> {
    // Try loading user config, fall back to defaults
    const userConfig = await orNullIfFileNotExist(
      this.loadUserConfig()
    );
    
    const projectConfig = await orIfFileNotExist(
      this.loadProjectConfig(),
      this.getDefaultProjectConfig()
    );
    
    // Merge configurations
    return {
      ...this.getDefaultConfig(),
      ...projectConfig,
      ...userConfig
    };
  }
  
  private async loadUserConfig() {
    const configPath = path.join(os.homedir(), ".myapp", "config.json");
    return JSON.parse(await fs.readFile(configPath, "utf8"));
  }
  
  private async loadProjectConfig() {
    return JSON.parse(await fs.readFile("./myapp.config.json", "utf8"));
  }
}

Error Collection and Reporting

import { NestedError } from "builder-util";

class ValidationEngine {
  async validateProject(projectPath: string): Promise<ValidationResult> {
    const errors: Array<Error> = [];
    const warnings: Array<string> = [];
    
    // Collect all validation errors
    try {
      await this.validatePackageJson(projectPath);
    } catch (error) {
      errors.push(error);
    }
    
    try {
      await this.validateTypeScript(projectPath);
    } catch (error) {
      errors.push(error);
    }
    
    try {
      await this.validateAssets(projectPath);
    } catch (error) {
      errors.push(error);
    }
    
    // Return results or throw aggregated error
    if (errors.length > 0) {
      throw new NestedError(errors, "Project validation failed:");
    }
    
    return {
      isValid: true,
      warnings
    };
  }
}