Justin Homes
Justin Homes

Reputation: 3799

Func for async goes in deadlock?

Objective:

I am using redis for cache and trying to get a cache value if not available get from repo and set the cache value.

Problem:

client side js keeps waiting forever and it seems to be in some type of deadlock

Code causing issue

   return await _cacheStore.GetAsync("CacheKey", new TimeSpan(24, 0, 0),
                 async () =>
                  await _repo.GetAllAsync()
                  );

Code that works, but kinda redundant as i keep using this pattern a lot of places.

    var data = await _cacheStore.GetAsync<List<objectType>>("cacheKey");
    if (data == null)
    {
        data = await _repo.GetAllAsync();
        _cacheStore.SetAsync<List<objectType>>("cacheKey", data, new TimeSpan(24, 0, 0));
    }
    return data;

//Possible Problem function below passing async method as Func????? Functions called by above code

public static async Task < T > GetAsync < T > (this IRedisCacheStore source, string key, TimeSpan time, Func < Task < T >> fetch) where T: class {
 if (source.Exists(key)) {
  return await source.GetAsync < T > (key);
 } else {
  var result = fetch();

  if (result != null) {
   source.Set(key, result, time);
  }

  return await result;
 }
}

public async Task < List < ObjectType >> GetAllAsync() {
 var result = await _procExecutor.ExecuteProcAsync < ObjectType > ("Sproc", null);

 return (result ? ? new List < ObjectType > ()).ToList();
}

public async Task < IEnumerable < TResult >> ExecuteProcAsync < TResult > (string sproc, object param) {
  using(var conn = _connection.GetConnection()) {
   return await conn.QueryAsync < TResult > (sproc, param, commandType: CommandType.StoredProcedure);
  }

Here is my redis cacheStore

public interface IRedisCacheStore
{
    bool Exists(string key);
    T Get<T>(string key);
    void Set<T>(string key, T value, TimeSpan expiredIn);
    void Remove(string key);

    Task<bool> ExistsAsync(string key);
    Task<T> GetAsync<T>(string key);
    Task SetAsync<T>(string key, T value, TimeSpan expiredIn);
    Task RemoveAsync(string key);
}

Upvotes: 2

Views: 372

Answers (1)

Evk
Evk

Reputation: 101633

The problem is here:

var result = fetch();

if (result != null) {
   source.Set(key, result, time);
} 

fetch() returns Task<T>, and that is what you are trying to store in Redis cache and Task is (obviously) not serializable. Just use:

var result = await fetch();

Upvotes: 3

Related Questions