#Conflicts of loggedInUser in typeorm event

48 messages · Page 1 of 1 (latest)

inner fox
#

I noticed some conflicts when retrieving loggedinuser infos in typeorm event.

I have registered the loggedinuser in a middleware

req.scope.register({ loggedInUser: { resolve: () => loggedInUser, }, });

and then I listen to beforeInsert event for products to add the store_id to the object

`@OnMedusaEntityEvent.Before.Insert(Product, { async: true })
public async beforeProductInsert(
params: MedusaEventHandlerParams<Product, "Insert">
): Promise<EntityEventType<Product, "Insert">> {
const { event } = params;

const loggedInUser = this.container.loggedInUser;
event.entity.store_id = loggedInUser.store_id;`

This is working most of the time but in 1% of the cases the wrong store_id is affected to the product. This is occuring especially if we do concurrent product creations by two different logged-in users.

@bold kernel did you already get this error ? Do you have a solution ?

bold kernel
#

If the scope of your service is scope or transient it shouldn’t happen. Maybe you are using a singleton? Also, when did you start using the extender and which version of the packages (extender, medusa) do you have?

inner fox
#

I did not define any scope indeed. I am using the extender since july 2022.
The current version of the project is

"medusa-extender": "^1.8.8",
"@medusajs/medusa": "^1.7.15",

We still have to upgrade to 1.8+

#

Can I define scope in my versions ?

bold kernel
#

Yes sure, by passing the scope in the decorator options, i am surprised that you missed it ☺️

inner fox
#

ah yes you are right it was already in it,

@Service({ scope: "SCOPED", override: MedusaProductService }) export class ProductService extends MedusaProductService { static Events = { UPDATED: "product.updated", CREATED: "product.created", DELETED: "product.deleted", };

So I have the issue with the service scope at "SCOPED" :/

bold kernel
#

In that case that is pretty weird as you should have then a new instance per incoming request

inner fox
#

The full beginning of the code of the service in case

`@Service({ scope: "SCOPED", override: MedusaProductService })
export class ProductService extends MedusaProductService {
static Events = {
UPDATED: "product.updated",
CREATED: "product.created",
DELETED: "product.deleted",
};
readonly #manager: EntityManager;
private readonly eventBus: EventBusService;
private readonly productRepository: typeof ProductRepository;
private readonly productVariantRepository: typeof ProductVariantRepository;
private readonly productVariantService: ProductVariantService;
private readonly imageRepository: typeof ImageRepository;
private readonly productTypeRepository: typeof ProductTypeRepository;
private readonly productTagRepository: typeof ProductTagRepository;
private readonly cartRepository: typeof CartRepository;
private readonly priceSelectionStrategy: any;

constructor(private readonly container: ConstructorParams) {
super(container);
this.#manager = container.manager;
this.eventBus = container.eventBusService;
this.productRepository = container.productRepository;
this.productVariantRepository = container.productVariantRepository;
this.productTypeRepository = container.productTypeRepository;
this.productTagRepository = container.productTagRepository;
this.imageRepository = container.imageRepository;
this.productVariantService = container.productVariantService;
this.cartRepository = container.cartRepository;
this.priceSelectionStrategy = container.priceSelectionStrategy;
}

@OnMedusaEntityEvent.Before.Insert(Product, { async: true })
public async beforeProductInsert(
params: MedusaEventHandlerParams<Product, "Insert">
): Promise<EntityEventType<Product, "Insert">> {
const { event } = params;

const loggedInUser = this.container.loggedInUser;`
bold kernel
#

Are you sure the logged in user is not the right one?

inner fox
#

I am quite sure yes

#

I am sure that the store_id is not the good one

#

but there is one store_id per user

bold kernel
#

So the product that is being created is not linked to the current loggedInUser that you get? Just trying to re formulate

inner fox
#

yes exactly

bold kernel
#

Humm, so far this has not been reported so i am bit surprised as it is used by many companies

inner fox
#

If

user1,store_id1 is creating product 1
user2,store_id2 is creating product 2

it happens that product_1.store_id = store_id2

bold kernel
#

How is your listener attached to the connection ? Through a middleware ?

#

Do you have other customisation ?

inner fox
#

The subscriber is attached through a middleware yes for product

#

@Middleware({ requireAuth: true, routes: [ { method: "post", path: "/admin/products" }, { method: "post", path: "/admin/customization/thank-you-card" }, { method: "delete", path: "/admin/products/:id" }, { method: "post", path: "/admin/products/:id" }, { method: "post", path: "/admin/customization/packaging-logo" }, { method: "post", path: "/admin/products/:id/variants" }, { method: "post", path: "/admin/products/:id/variants/:variant_id", }, ], }) export default class AttachProductSubscribersMiddleware implements MedusaMiddleware { public consume( req: MedusaAuthenticatedRequest | Request, res: Response, next: NextFunction ): void | Promise<void> { const { connection } = req.scope.resolve(MEDUSA_RESOLVER_KEYS.manager) as { connection: Connection; }; MedusaUtils.attachOrReplaceEntitySubscriber(connection, ProductSubscriber); MedusaUtils.attachOrReplaceEntitySubscriber( connection, ProductVariantSubscriber ); return next(); } }

inner fox
bold kernel
#

For the product creation end point for example

#

Also, can you try ProductSubscriber.attachTo from your service constructor

#

Just to see if there is any difference

inner fox
bold kernel
#

What i don’t understand is that i have an integration tests that fire concurrent requests and validate the calls and results 🤔

inner fox
bold kernel
#

Yes you delete from the middleware and move it to the service constructor just like the example in the doc

inner fox
#

do you have the link of that doc by any chance?

should I move just this

MedusaUtils.attachOrReplaceEntitySubscriber(connection, ProductSubscriber);

or the entire middleware ?

Also could it be that it's a conflict between the middleware ? the product and the user one

bold kernel
#
GitHub

:syringe: Medusa on steroid, take your medusa project to the next level with some badass features :rocket: - medusa-extender/integration-tests/tests/fixtures/event-subscribers.ts at main · adrien2p...

The extender provides an out-of-the-box application architecture which allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications.
In also increase medusa extensibility and customisation for special use cases. It comes with handy
decorators approach to increase the DX and full typings s...

inner fox
#

thanks!

bold kernel
#

Let me know 💪

inner fox
#

Yes sure

#

I just put it and it seems to work but I can't reproduce the error all the time. So i'll monitor that and let you know if it solved the issue

#

thanks for your time

#

I hope it does 🤞

inner fox
#

I console.logged the loggedinuser and indeed we have the same one even if we were two different users logged in but creating the products at the same time

#

these are the console.log of the two typeorm event fired exactly at the same timestamp

#

The product.subscriber.ts looks like that if that helps

`@EventSubscriber()
export default class ProductSubscriber implements EntitySubscriberInterface {
static attachTo(connection: Connection): void {
Utils.attachOrReplaceEntitySubscriber(connection, ProductSubscriber);
}

public listenTo(): typeof Product {
return Product;
}

/**

  • Relay the event to the handlers.
  • @param event Event to pass to the event handler
    */
    public async beforeInsert(event: InsertEvent<Product>): Promise<void> {
    return await eventEmitter.emitAsync(
    OnMedusaEntityEvent.Before.InsertEvent(Product),
    {
    event,
    transactionalEntityManager: event.manager,
    }
    );
    }`
bold kernel
#

Unfortunately i don’t have the bandwidth at the moment to investigate deep in it. I suggest that you use the middleware to add the store_id to the body so that it is still managed server side, and override the validator to accept the store id. Instead of using the event emmiter

#

Alternatively, you can override the service create method to attach the store_id to the data and then call super.create with the arguments. Which might be easier

inner fox
bold kernel
#

yes and then you ll have to migrate to a full medusa setup without the extender and you ll have to do the same as my suggestions. Just to be sure, have you seen that the extender is deprecated?

inner fox
#

yes thanks it's on our plans to migrate to medusa 1.8+ and get rid of the extender this summer. By the way, is there a migration guide to go from extender to medusa 1.8 ?

bold kernel
#

There is no propoer guide but it is pretty easy to do by looking at the medusa documentation. Otherwise i ve answer a lot of discussion on that topic but if you don’t find the solution you can ask ☺️

inner fox
#

Ok I will do that - many thanks