Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major bug, request scope in a singleton class is not working #1549

Open
veeramarni opened this issue Dec 31, 2023 · 1 comment
Open

Major bug, request scope in a singleton class is not working #1549

veeramarni opened this issue Dec 31, 2023 · 1 comment

Comments

@veeramarni
Copy link

veeramarni commented Dec 31, 2023

request-scoped dependency is not working in a singleton class.

Expected Behavior

Writing a test case to validate the behavior of a singleton class with a request-scoped dependency involves simulating different request contexts and verifying that the singleton class behaves according to the request-scoped dependency. Here's a basic example using a hypothetical Node.js environment with Inversify for dependency injection and a testing framework like Jest.

Current Behavior

Request scope dependency is not refreshing with new value.

Steps to Reproduce (for bugs)

Singleton Service: MySingletonService is a singleton and should be the same instance in both contexts.
Request-Scoped Dependency: MyRequestScopedDependency is request-scoped, so it should have different values in different contexts.

import { Container, inject, injectable } from 'inversify';
import 'reflect-metadata';
import { Context } from 'inversify/lib/planning/context';

const TYPES = {
    MyRequestScopedDependency: Symbol.for('MyRequestScopedDependency'),
    MySingletonService: Symbol.for('MySingletonService'),
};

@injectable()
class MyRequestScopedDependency {
    public value: number;

    constructor() {
        this.value = Math.random();
    }
}

@injectable()
class MySingletonService {
    private requestScopedDependency: MyRequestScopedDependency;

    constructor(@inject(TYPES.MyRequestScopedDependency) requestScopedDependency: MyRequestScopedDependency) {
        this.requestScopedDependency = requestScopedDependency;
    }

    getRequestScopedValue() {
        return this.requestScopedDependency.value;
    }
}

const container = new Container();
container
    .bind<MyRequestScopedDependency>(TYPES.MyRequestScopedDependency)
    .to(MyRequestScopedDependency)
    .inRequestScope();
container.bind<MySingletonService>(TYPES.MySingletonService).to(MySingletonService).inSingletonScope();


describe('Singleton with Request-Scoped Dependency', () => {
    it('should have different request-scoped dependencies in different contexts', () => {
        // Simulate two different requests
        const request1Context = new Context(container);
        const request2Context = new Context(container);

        const singletonService1 = request1Context.container.get<MySingletonService>(TYPES.MySingletonService);
        const singletonService2 = request2Context.container.get<MySingletonService>(TYPES.MySingletonService);

        // Both instances should be the same (singleton)
        expect(singletonService1).toBe(singletonService2);
        console.log('VALUE__', singletonService1.getRequestScopedValue(), singletonService2.getRequestScopedValue() )
        // But their request-scoped dependencies should be different <----THIS TEST FAILS
        expect(singletonService1.getRequestScopedValue()).not.toBe(singletonService2.getRequestScopedValue());
    });
});


Your Environment

  • Version used: 6.0.2
  • Environment name and version (e.g. Chrome 39, node.js 5.4): nodjes 18
  • Operating System and version (desktop or mobile): Macos
@veeramarni
Copy link
Author

This might be my workaround

const TYPES = {
    RequestScopedDependencyFactory: Symbol.for('RequestScopedDependencyFactory'),
    MyRequestScopedDependency: Symbol.for('MyRequestScopedDependency'),
    MySingletonService: Symbol.for('MySingletonService'),
};

@injectable()
class MyRequestScopedDependency {
    public value: number;

    constructor() {
        this.value = Math.random();
    }
}

@injectable()
class MySingletonService {
    private getRequestScopedDependency: () => MyRequestScopedDependency;

    constructor(
        @inject(TYPES.RequestScopedDependencyFactory)
        getRequestScopedDependencyFactory: () => MyRequestScopedDependency,
    ) {
        this.getRequestScopedDependency = getRequestScopedDependencyFactory;
    }

    getRequestScopedValue() {
        return this.getRequestScopedDependency().value;
    }
}

const container = new Container();

container
    .bind<() => MyRequestScopedDependency>(TYPES.RequestScopedDependencyFactory)
    .toFactory<MyRequestScopedDependency>(
        (context: interfaces.Context) => () =>
            context.container.get<MyRequestScopedDependency>(TYPES.MyRequestScopedDependency),
    );

container
    .bind<MyRequestScopedDependency>(TYPES.MyRequestScopedDependency)
    .to(MyRequestScopedDependency)
    .inRequestScope();
container.bind<MySingletonService>(TYPES.MySingletonService).to(MySingletonService).inSingletonScope();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant