We are facing the perforamce issue on creation /modification of users when we have lots of locations and mappings.
- We are currently working with domain events and handling them using ILocalEventHandler<T> for both the IdentityUserOrganizationUnit and IdentityUserRole entities. Specifically, we are successfully using the following local event handlers: ILocalEventHandler<EntityCreatedEventData<IdentityUserOrganizationUnit>> ILocalEventHandler<EntityCreatedEventData<IdentityUserRole>>
These local event handlers are functioning as expected within the same application context.
As we transition to a distributed architecture using RabbitMQ, we are attempting to handle the same events through the distributed event bus, using: IDistributedEventHandler<EntityCreatedEventData<IdentityUserOrganizationUnit>> IDistributedEventHandler<EntityCreatedEventData<IdentityUserRole>>
However, we have encountered the following challenges: These events are not automatically published to the distributed event bus. Did not find any ETOs for the IdentityUserOrganizationUnit or IdentityUserRole entities. As a result, we are unable to subscribe to or handle these events using the distributed event.
- We've observed a significant performance issue when assigning or unassigning roles and organization units to users in our application. Specifically, during user creation or editing, the LocalEventHandler is triggered for every individual role or organization unit assignment or removal.
In scenarios where a user is associated with hundreds of roles or organization units, this results in the UserManager making repeated changes per item — leading to hundreds of operations and drastically increasing the time required to complete the user creation/edit process.
Are there best practices within ABP for improving performance in such scenarios?
Any guidance or clarification on this would be greatly appreciated.
2 Answer(s)
-
0
In ABP, local events (ILocalEventHandler<T>) are only published and handled within the same application boundary and are not automatically forwarded to the distributed event bus. For distributed event handling (IDistributedEventHandler<T>), you must explicitly publish events as ETOs (Event Transfer Objects) designed for cross-service communication. The IdentityUserOrganizationUnit and IdentityUserRole entities do not have built-in ETOs, so their changes are not automatically published to the distributed event bus. To enable distributed eventing for these entities, you should:
- Define custom ETOs representing the data you want to transfer.
- Publish these ETOs manually in your application logic when changes occur (e.g., after assigning/removing roles or organization units).
- Subscribe to these ETOs in other microservices using IDistributedEventHandler<T>.
Regarding performance: The default ABP implementation triggers a local event for every single assignment or removal, which can cause performance issues when processing hundreds of roles or organization units. Best practices to improve performance in such scenarios include:
- Batch Processing: Instead of triggering an event per assignment, aggregate changes and trigger a single event for all assignments/removals. You can implement your own logic to batch these operations and publish a single event containing all changes.
- Minimize Event Handler Logic: Ensure your event handlers are lightweight and avoid heavy operations or synchronous database calls inside the handler.
- Use Outbox/Inbox Pattern: For distributed events, use the Outbox/Inbox pattern to ensure reliable and transactional event publishing/handling, which can also help with throughput and reliability in high-volume scenarios.
- Consider Disabling Automatic Events: If you do not need per-assignment events, consider disabling or customizing the event publishing logic to reduce the number of events.
Example: Custom ETO and Manual Publishing
public class UserRolesChangedEto { public Guid UserId { get; set; } public List<Guid> AddedRoleIds { get; set; } public List<Guid> RemovedRoleIds { get; set; } } // When updating user roles: await _distributedEventBus.PublishAsync(new UserRolesChangedEto { UserId = userId, AddedRoleIds = addedRoles, RemovedRoleIds = removedRoles });
For more details:
- Event Transfer Object (ETO) for Distributed Events
- Outbox/Inbox for Transactional Events
- Notice and Solve ABP Distributed Events Disordering
These approaches will help you optimize event handling and improve user transaction performance in high-volume scenarios.
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
-
0
hi
The distributed events are:
- EntityCreatedEto<T> is published when an entity of type T was created.
- EntityUpdatedEto<T> is published when an entity of type T was updated.
- EntityDeletedEto<T> is published when an entity of type T was deleted.
See https://abp.io/docs/9.3/framework/infrastructure/event-bus/distributed#event-types
In scenarios where a user is associated with hundreds of roles or organization units, this results in the UserManager making repeated changes per item — leading to hundreds of operations and drastically increasing the time required to complete the user creation/edit process.
Can you share the code?
Thanks