reuse

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package reuse provides a generic resource reuse mechanism with automatic lifecycle management. It manages the lifecycle of a shared resource with automatic cleanup and reuse, providing thread-safe access to resources that can be used by multiple concurrent users.

The package provides:

  • Reuse type for managing resource lifecycle
  • Automatic resource creation and cleanup
  • Thread-safe concurrent access
  • Flexible configuration options
  • Support for different cleanup strategies

Example Usage:

reuse := reuse.Run(
    func() (*MyResource, error) {
        return &MyResource{}, nil
    },
    reuse.WithCleanupTimeout(10*time.Second),
)

entered, err := reuse.Enter(ctx)
if err != nil {
    return err
}
defer entered.Exit()

resource := entered.Value()
// Use resource...

Index

Constants

View Source
const (
	// WeightUnlimited indicates no limit on concurrent users in the reuse instance.
	// Use this value with WithWeight to disable concurrency limiting.
	WeightUnlimited = -1
)

Variables

View Source
var ErrReuseIsClosed = errors.New("reuse instance is closed")

ErrReuseIsClosed is returned when trying to enter a reuse instance that has been closed.

View Source
var ErrShutdown = errors.New("reuse in shutdown phase, any enter is blocked")

ErrShutdown is returned when trying to enter a reuse instance that is in shutdown phase. This error indicates that the instance is no longer accepting new users.

Functions

This section is empty.

Types

type CleanupFunc

type CleanupFunc[T any] func(context.Context, T) error

CleanupFunc is a function that performs custom cleanup on a resource. It is called before the built-in cleanup logic (Close/Terminate methods). This allows for additional cleanup operations beyond the standard Close/Terminate.

Parameters:

  • ctx: Context for the cleanup operation, can be used for cancellation
  • value: The resource to clean up

If an error is returned, it will be logged but the built-in cleanup will still proceed.

type Cleanupper

type Cleanupper interface {
	// Cleanup registers a function to be called when the test completes.
	// This is used to ensure resources are properly cleaned up after tests.
	Cleanup(doCleanup func())
}

Cleanupper is an interface for registering cleanup functions. This is typically implemented by *testing.T to integrate with test cleanup.

type Config

type Config[T any] struct {
	// contains filtered or unexported fields
}

Config holds the configuration options for a reuse instance. These options control behavior such as cleanup timing, concurrency limits, logging, and resource creation.

type CreateFunc

type CreateFunc[T any] func() (T, error)

CreateFunc is a function type that creates a new instance of type T. It's used by the reuse instance to create resources on-demand when the first user enters and no resource exists yet.

The function should return a new resource instance and any error that occurred during creation. If an error is returned, the Enter operation will fail.

Example:

createFunc := func() (*MyResource, error) {
    return &MyResource{ID: uuid.New()}, nil
}

type Entered

type Entered[T any] struct {
	// contains filtered or unexported fields
}

Entered represents a successful entry into a reuse instance. It provides access to the resource and a way to exit when done.

Entered instances should be used with defer to ensure cleanup:

entered, err := reuse.Enter(ctx)
if err != nil {
    return err
}
defer entered.Exit()

resource := entered.Value()
// Use resource...

func (Entered[T]) Exit

func (e Entered[T]) Exit()

Exit releases the resource back to the reuse instance. This decrements the user count and may trigger cleanup if this was the last user.

Exit should be called when the caller is done using the resource. It's safe to call Exit multiple times, but only the first call has an effect.

func (Entered[T]) Value

func (e Entered[T]) Value() T

Value returns the resource instance that was entered. This can be used to access the resource for operations.

The returned value is valid until Exit is called.

type Option

type Option[T any] func(*Config[T])

Option is a function that configures a reuse instance. Options can be passed to Run to customize the instance's behavior.

func WithCleanupFunc

func WithCleanupFunc[T any](cleanupFunc CleanupFunc[T]) Option[T]

WithCleanupFunc sets a custom cleanup function that is called before the built-in cleanup logic (Close/Terminate methods).

Default: nil (no custom cleanup function)

The custom cleanup function is called first during cleanup, followed by the built-in cleanup. This allows you to perform additional cleanup operations such as releasing external resources, notifying other systems, or logging.

If the cleanup function returns an error, it will be logged but cleanup will continue with the built-in Close/Terminate method.

Example:

reuse := Run(createFunc,
	WithCleanupFunc(func(ctx context.Context, r *MyResource) error {
		// Custom cleanup logic here
		r.ReleaseExternalResources()
		return nil
	}),
)

func WithCleanupTimeout

func WithCleanupTimeout[T any](cleanupTimeout time.Duration) Option[T]

WithCleanupTimeout sets the maximum duration to wait for cleanup operations.

Default: 5 * time.Second

Example:

reuse := Run(createFunc, WithCleanupTimeout(10*time.Second))

func WithLogger

func WithLogger[T any](logger *log.Logger) Option[T]

WithLogger sets a custom logger for logging phase changes and commands.

Default: logger that writes to io.Discard (no logging)

Example:

logger := log.New(os.Stdout, "reuse: ", log.LstdFlags)
reuse := Run(createFunc, WithLogger(logger))

func WithManualCleanup

func WithManualCleanup[T any](manualCleanup bool) Option[T]

WithManualCleanup determines whether cleanup is automatic or manual.

Default: false (automatic cleanup)

When false: Cleanup happens automatically after waitUntilCleanup duration. When true: Cleanup must be triggered explicitly by calling Cleanup().

Example:

// Manual cleanup mode
reuse := Run(createFunc, WithManualCleanup(true))
// Later, trigger cleanup explicitly
reuse.Shutdown() or reuse.Kill()

func WithWaitUntilCleanup

func WithWaitUntilCleanup[T any](waitDuration time.Duration) Option[T]

WithWaitUntilCleanup sets how long to wait after the last user exits before cleanup. This grace period allows new users to reuse the resource before it's cleaned up.

Default: 1 * time.Second

Example:

reuse := Run(createFunc, WithWaitUntilCleanup(30*time.Second))

func WithWeight

func WithWeight[T any](weight int) Option[T]

WithWeight limits the number of concurrent users. Use WeightUnlimited (-1) for no limit.

Default: WeightUnlimited (no limit)

When weight > 0, it acts as a semaphore. Enter will block if the limit is reached.

Example:

// Allow up to 10 concurrent users
reuse := Run(createFunc, WithWeight(10))

type Reuse

type Reuse[T any] struct {
	// contains filtered or unexported fields
}

Reuse manages the lifecycle of a shared resource with automatic cleanup and reuse. It provides thread-safe access to resources that can be used by multiple concurrent users.

Reuse implements a phase-based state machine to manage resource lifecycle:

  • Initial: Resource not yet created
  • Active: Resource created and being used
  • WaitUntilCleanup: All users exited, waiting for grace period
  • Shutdown: Instance is shutting down

func Run

func Run[T any](
	createFunc CreateFunc[T],
	opts ...Option[T],
) *Reuse[T]

Run T must be safe to use by many goroutines Run creates and starts a new reuse instance with the given configuration. This is the primary constructor for creating reuse instances.

Parameters:

  • createFunc: Factory function that creates new resource instances
  • opts: Optional configuration options

Returns:

  • *Reuse[T]: A new reuse instance ready for use

Example:

reuse := Run(
	func() (*MyResource, error) {
	    return &MyResource{}, nil
	},
	WithCleanupTimeout(10*time.Second),
	WithWeight(5), // Limit to 5 concurrent users
)

func RunForTesting

func RunForTesting[T any](
	cleanupper Cleanupper,
	createFunc CreateFunc[T],
	opts ...Option[T],
) *Reuse[T]

RunForTesting creates a reuse instance for use in tests with automatic cleanup. This is a convenience function that integrates with testing frameworks to ensure resources are properly cleaned up after tests complete.

Parameters:

  • cleanupper: Interface for registering cleanup (typically *testing.T)
  • createFunc: Factory function that creates new resource instances
  • opts: Optional configuration options

Returns:

  • *Reuse[T]: A new reuse instance with automatic cleanup registered

The function automatically registers the reuse.Shutdown method as a cleanup function, ensuring resources are properly released when the test completes.

Example:

func TestWithReuse(t *testing.T) {
	reuse := RunForTesting(t,
		func() (*MyResource, error) {
			return &MyResource{}, nil
		},
		WithWeight(5),
	)
	// reuse will be automatically shut down when test completes

	entered, err := reuse.Enter(ctx)
	require.NoError(t, err)
	defer entered.Exit()

	// Use resource in test...
}

func (*Reuse[T]) Enter

func (r *Reuse[T]) Enter(ctx context.Context) (Entered[T], error)

Enter attempts to enter the reuse instance and access the resource. If successful, it returns an Entered instance that provides access to the resource.

Enter blocks until:

  • The resource is available (if weight limit is set)
  • The resource is created (if this is the first user)
  • Context is canceled

Parameters:

  • ctx: Context for cancellation and timeout

Returns:

  • Entered[T]: Provides access to the resource
  • error: Non-nil if entry fails (e.g., instance is shutdown)

Example:

entered, err := reuse.Enter(ctx)
if err != nil {
    return err
}
defer entered.Exit()

resource := entered.Value()
// Use resource...

func (*Reuse[T]) Kill

func (r *Reuse[T]) Kill()

Kill forcefully terminates the reuse instance. This immediately stops all operations, cleans up resources, and does not wait for existing users to exit.

Kill should only be used in emergency situations or when immediate cleanup is required. For graceful shutdown, use Shutdown instead.

func (*Reuse[T]) Shutdown

func (r *Reuse[T]) Shutdown()

Shutdown gracefully shuts down the reuse instance. This stops accepting new users and waits for existing users to exit before cleanup.

Shutdown is safe to call multiple times - subsequent calls have no effect. This is the preferred way to stop a reuse instance.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL