Hi support team,
I'm currently focusing on EF queries optimization, specially for read only queries. I realized that EF queries like this one :
await _entityRepository.getAll().Include(e => e.NestedEntity).OrderBy(input.Sorting).PageBy(input).ToListAsync()
is causing database delays because SQL engine tries to get every properties from entity (event more if a nested entity is included in the query).
After some tests, I achieve a query 4x times faster by selecting only needed entity properties like that :
await _entityRepository.getAll().Include(e => e.NestedEntity).Select(e => new EntityDto { Id = e.Id, Description = e.Description}).OrderBy(input.Sorting).PageBy(input).ToListAsync()
As you can see, I'm using a DTO (EntityDto) to map from Entity object (this is called "projection"). My goal is to reuse all existing DTO's to optimize all select queries ; BUT I'm doing the mapping manually, which can cause errors in the future (ex : if a new property is added to the DTO). I need this to be more maintainable and optimized.
Do you have a solution to automatically map the DTO in the SELECT statement of the query ?
Hi abp team,
I'm getting following error several times per day :
ERROR 2022-02-11 10:24:53,841 [86 ] me.Caching.Redis.AbpPerRequestRedisCache - System.ObjectDisposedException: IFeatureCollection has been disposed.
Object name: 'Collection'.
at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.ThrowContextDisposed()
at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Items()
at Abp.Runtime.Caching.Redis.AbpPerRequestRedisCache.TryGetValueAsync(String key)
at Abp.Runtime.Caching.AbpCacheBase`2.GetAsync(TKey key, Func`2 factory)
System.ObjectDisposedException: IFeatureCollection has been disposed.
Object name: 'Collection'.
at Microsoft.AspNetCore.Http.Features.FeatureReferences`1.ThrowContextDisposed()
at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Items()
at Abp.Runtime.Caching.Redis.AbpPerRequestRedisCache.TryGetValueAsync(String key)
at Abp.Runtime.Caching.AbpCacheBase`2.GetAsync(TKey key, Func`2 factory)
Is it a problem we can fix ? Is it due to redis data expiration policy ?
Hi,
As you know from my previous questions, I'm facing many performance issues while adding new users to the app. I'm dealing with multi instance on Azure, Redis cache, Azure SignalR...
The problem here is that some requests are very long to execute. Please look at following example :
As you can see, the request is blocked for 10s on token validation... On the left side of the screenshot you can see thaat the same request can be very fast. I suspect a lock somewhere in the app because all Azure resources are good (CPU, RAM...).
It is very hard to find the root cause from my side.
Can you please provide some help to find a solution ?
Hi support team,
I'm facing performance issues on Azure. While investigating requests performances, I noticed that a lot of requests where slow due to token validation. The AbpUserTokens table has arround 50k records which is a lot and very bad for performance. All records are still valid : so that means that the job in charge of deleting expired tokens is working.
I had a look to similar issues in the past : https://support.aspnetzero.com/QA/Questions/9009/Bad-performance-on-Azure-App-Service https://support.aspnetzero.com/QA/Questions/10545/Token-Authenticate-time-out-after-long-time-usage-with-same-user https://github.com/aspnetzero/aspnet-zero-core/issues/2925 https://github.com/aspnetzero/aspnet-zero-core/issues/2926
For you information, my refreshtoken expriration is fixed to one year... the angular web app AND the mobile app are not using it (these apps have been updated from an old Zero version that was not using refresh tokens at this time). Therefore, only few API clients are using it.
Right now, I plan to delete the whole table and get some performance back. What do you think ? Is it bad to do it ?
I plan also to change refresh tokens expiration to one month.
Even so, if I let it like that, I will have the same issue after some time... what is your advice to avoid this issue ? I think that a lot of Abp apps are facing the same.
Hi,
I'm getting some logged errors due to Redis cache timeout. The UI shows a message "InternalServerError". Here is the log :
WARN 2021-12-08 08:21:43,756 [102 ] Abp.MultiTenancy.TenantResolver - StackExchange.Redis.RedisTimeoutException: Timeout performing GET (5000ms), inst: 0, qu: 19, qs: 0, aw: False, bw: Inactive, rs: ReadAsync, ws: Idle, in: 0, serverEndpoint: redis.cache.windows.net:6380, mc: 1/1/0, mgr: 10 of 10 available, clientName: , IOCP: (Busy=0,Free=1000,Min=1,Max=1000), WORKER: (Busy=17,Free=32750,Min=1,Max=32767), v: 2.2.62.27853 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)
at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor`1 processor, ServerEndPoint server) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 2851
at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor`1 processor, ServerEndPoint server) in /_/src/StackExchange.Redis/RedisBase.cs:line 54
at StackExchange.Redis.RedisDatabase.StringGet(RedisKey key, CommandFlags flags) in /_/src/StackExchange.Redis/RedisDatabase.cs:line 2409
at Abp.Runtime.Caching.Redis.AbpRedisCache.TryGetValue(String key, Object& value)
at Abp.Runtime.Caching.AbpCacheBase`2.Get(TKey key, Func`2 factory)
at Abp.Runtime.Caching.TypedCacheWrapper`2.Get(TKey key, Func`2 factory)
at Abp.MultiTenancy.TenantCache`2.GetOrNull(String tenancyName)
at Abp.MultiTenancy.TenantStore.Find(String tenancyName)
at Abp.AspNetCore.MultiTenancy.DomainTenantResolveContributor.ResolveTenantId()
at Abp.MultiTenancy.TenantResolver.GetTenantIdFromContributors()
StackExchange.Redis.RedisTimeoutException: Timeout performing GET (5000ms), inst: 0, qu: 19, qs: 0, aw: False, bw: Inactive, rs: ReadAsync, ws: Idle, in: 0, serverEndpoint: redis.cache.windows.net:6380, mc: 1/1/0, mgr: 10 of 10 available, clientName: , IOCP: (Busy=0,Free=1000,Min=1,Max=1000), WORKER: (Busy=17,Free=32750,Min=1,Max=32767), v: 2.2.62.27853 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)
at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor`1 processor, ServerEndPoint server) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 2851
at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor`1 processor, ServerEndPoint server) in /_/src/StackExchange.Redis/RedisBase.cs:line 54
at StackExchange.Redis.RedisDatabase.StringGet(RedisKey key, CommandFlags flags) in /_/src/StackExchange.Redis/RedisDatabase.cs:line 2409
at Abp.Runtime.Caching.Redis.AbpRedisCache.TryGetValue(String key, Object& value)
at Abp.Runtime.Caching.AbpCacheBase`2.Get(TKey key, Func`2 factory)
at Abp.Runtime.Caching.TypedCacheWrapper`2.Get(TKey key, Func`2 factory)
at Abp.MultiTenancy.TenantCache`2.GetOrNull(String tenancyName)
at Abp.MultiTenancy.TenantStore.Find(String tenancyName)
at Abp.AspNetCore.MultiTenancy.DomainTenantResolveContributor.ResolveTenantId()
at Abp.MultiTenancy.TenantResolver.GetTenantIdFromContributors()
Do you think that this can be linked with multiple requests to Redis due to GetAll requests ? Is "Per Request Redis Cache" implementation will solve that ?
Hi,
I'm getting very long request issues with GetProfilePictureByUserId endpoint. Sometimes more than 1 min ! Here is an example from Azure insights :
As you can see, a lot of time is "waste" before accessing database (which is very short time access).
I slightly change GetProfilePictureByUserId to implement a cache mechanism. Here is the code :
public async Task<GetProfilePictureOutput> GetProfilePictureByUserId(long userId)
{
//Get from cache first
var outputFromCache = await _cacheManager.GetCache(UserPictureByUserIdCacheName).GetOrDefaultAsync(userId.ToString()) as GetProfilePictureOutput;
if (outputFromCache != null)
return outputFromCache;
else
{
var user = await UserManager.GetUserByIdAsync(userId);
if (user.ProfilePictureId == null)
{
return new GetProfilePictureOutput(string.Empty);
}
var output = await GetProfilePictureById(user.ProfilePictureId.Value);
//Set cache
await _cacheManager.GetCache(UserPictureByUserIdCacheName).SetAsync(userId.ToString(), output);
return output;
}
}
When testing this code, it runs very fast. But on production, a lot of requests gets stuck sometimes. I'm using Redis cache with azure app service in 2 instances.
I have the same issues with other endpoints like :
All this seems to be linked with cache management. This is frustrating because the app can be very slow time to time and frustrating lots of users.
I tried to use AbpPerRequestRedisCache but it is throwing exceptions at the moment...
How can I fix this ?
ABP 6.4 Angular .NET 5
Hi,
I'm using zero for a while now and the journey for getting a performant app is quite hard :) As the trafic grows, I had to switch SignalR from self hosted to dedicated service. I also had to configure app scaling according to trafic load. I'm running on Azure and my app is currently scaling out to 2 or 3 instances.
Multi-instances means also cache issues... then I switch MemoryCache to RedisCache. Every thing works as expected on production but the app is, at least, two times slower when it comes to get information from cache. GetAll method access as increased a lot...
I've followed all previous post about Redis performance and AbpPerRequestRedisCache.
Should I use AbpPerRequestRedisCache for the entire project ? What happens if a tenant setting is changed in one instance ? The other instances will not be aware of it and will use invalid data no ?
I've tried to test it by following the docs : https://aspnetboilerplate.com/Pages/Documents/PerRequestRedisCache I was able to download nuget package and add [DependsOn(typeof(AbpAspNetCorePerRequestRedisCacheModule))] but I don't found the way to activate option usePerRequestRedisCache to true
Configuration.Caching.UseRedis(usePerRequestRedisCache: true);
How can I activate it ?
Sorry for all that questions but app performance is really sensitive for all users
Hi support team,
I've implemented webhooks system on my dev machine. Everything works as exptected.
My question is how does this behave with multiple intance ? Don't we have a risk that a webhook is executed twice or more if multiple instance are active ?
I'm currently having some issues when switching to 2 or more instances like cache management and related features. This is also leading to performance issues...
I know that some related issues are existing in your github repos (aspboilerplate and zero), thus, I would like your advice before planning a deployment on production.
Tks
Hi,
I'm getting some warning exceptions with background workers. Can you please advise ?
Here is the exception :
WARN 2021-11-09 13:33:48,021 [76 ] Abp.BackgroundJobs.BackgroundJobManager - Abp.Domain.Uow.AbpDbConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
---> Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagationAsync(Int32 commandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Abp.EntityFrameworkCore.AbpDbContext.SaveChangesAsync(CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Abp.EntityFrameworkCore.AbpDbContext.SaveChangesAsync(CancellationToken cancellationToken)
at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext`3.SaveChangesAsync(CancellationToken cancellationToken)
at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChangesAsync()
at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.CompleteUowAsync()
at Abp.Domain.Uow.UnitOfWorkBase.CompleteAsync()
at Abp.Domain.Uow.UnitOfWorkManagerExtensions.WithUnitOfWorkAsync[TResult](IUnitOfWorkManager manager, Func`1 action, UnitOfWorkOptions options)
at Abp.BackgroundJobs.BackgroundJobStore.UpdateAsync(BackgroundJobInfo jobInfo)
at Abp.BackgroundJobs.BackgroundJobManager.TryUpdateAsync(BackgroundJobInfo jobInfo)
Abp.Domain.Uow.AbpDbConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
---> Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagationAsync(Int32 commandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
at Abp.EntityFrameworkCore.AbpDbContext.SaveChangesAsync(CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Abp.EntityFrameworkCore.AbpDbContext.SaveChangesAsync(CancellationToken cancellationToken)
at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext`3.SaveChangesAsync(CancellationToken cancellationToken)
at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChangesAsync()
at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.CompleteUowAsync()
at Abp.Domain.Uow.UnitOfWorkBase.CompleteAsync()
at Abp.Domain.Uow.UnitOfWorkManagerExtensions.WithUnitOfWorkAsync[TResult](IUnitOfWorkManager manager, Func`1 action, UnitOfWorkOptions options)
at Abp.BackgroundJobs.BackgroundJobStore.UpdateAsync(BackgroundJobInfo jobInfo)
at Abp.BackgroundJobs.BackgroundJobManager.TryUpdateAsync(BackgroundJobInfo jobInfo)
Xamarin Forms 4.8 Abp 6.4
Hi @Alper,
A lot of users are getting more and more exceptions on Xamarin Forms Android app like this : https://support.aspnetzero.com/QA/Questions/8484/Android-OnStart-crash The app is on the play store since a long time now and is working well most of the time. I never found the way to reproduce the exception reported by Google... but some days ago we had these exceptions with a new Nexus 5.
Therefore I hope you can help me to found a solution and fix the issue with the details above :
The exception happens in the following usecase :
Here is the Android exception logged :
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: FATAL EXCEPTION: main
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: Process: com.MyApp.Mobile, PID: 11020
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: android.runtime.JavaProxyThrowable: System.NullReferenceException: Object reference not set to an instance of an object
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at MyORG.MyApp.Core.Dependency.DependencyResolver.Resolve[T] () [0x00005] in <1174882f65d4478c861b92e9fc0bd083>:0
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at MyORG.MyApp.App.OnStart () [0x0010a] in <1174882f65d4478c861b92e9fc0bd083>:0
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_0 (System.Object state) [0x00000] in <1b39a03c32ec46258a7821e202e0269f>:0
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in <b868e022fd60450992c00cdaff974113>:0
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <b868e022fd60450992c00cdaff974113>:0
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <b868e022fd60450992c00cdaff974113>:0
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.37(intptr,intptr)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at mono.java.lang.RunnableImplementor.n_run(Native Method)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:30)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:938)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7842)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
> 11-06 06:37:48.437 11020 11020 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
The exception seems to happen while calling :
await DependencyResolver.Resolve<INavigationService>().InitializeAsync();
Do you know why INavigationService could be null only on app restarts in that specific usecase ?
Could this be linked with the SplashActivity OnResume() when calling
ApplicationBootstrapper.InitializeIfNeeds<XamarinAndroidModule>()
.