Skip to content

Centralize connection usage #47

@petermasking

Description

@petermasking

Currently, all packages that perform actions requiring a connection follow this repetitive pattern:

class SomeClass
{
    async doSomething(): Promise<void>
    {
        this.#logger?.debug(this.#logPrefix, 'Starting doing something');

        try
        {
            this.#validateConnection(); // Throws `NotConnected` if not connected
        
            await this.#performAction();

            this.#logger?.debug(this.#logPrefix, 'Finished doing something');
        }
        catch (error)
        {
            this.#logger?.error(this.#logPrefix, 'Doing something failed with error', error);

            throw error;
        }
    }
}

About 95% of this code is boilerplate: logging, try/catch, and connection validation. As the number of packages grows, we should centralize this pattern to reduce duplication.

There are two common approaches:

  1. TypeScript decorators – clean but experimental; not aligned with our goal of using only native JS constructs.
  2. Wrapper function – safe and fully compatible with current TS/JS standards.

We propose extending the connection package with a base class that provides a reusable execute method, centralizing the connection and logging patterns:

class Connectable
{
    #logger: Logger;
    #connected: false;

    constructor(logger: Logger)
    {
        this.#logger = logger;
    }

    async connect(action: () => Promise<T>)
    {
         // implement pattern with action execution
    }

    async disconnect(action: () => Promise<T>)
    {
         // implement pattern with action execution
    }

    async execute(actionName: string, action: () => Promise<T>): Promise<T>
    {
        // implement pattern with action execution
    }
}

This can can be used like this:

class SomeClass extends Connectable
{
    async doSomething(): Promise<void>
    {
        return this.execute('something', () => this.#performAction());
    }
}

This approach:

  1. Reduces boilerplate in all connection-based packages.
  2. Centralizes connect and disconnect handling.
  3. Makes future actions easier to implement with consistent observability.

Metadata

Metadata

Assignees

No one assigned

    Labels

    connectionAll connection package related issues.

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions