i have following code use information cache. dont know if maybe app opening many connections or error due transient failure on azure redis cache.
this stack trace
[redisconnectionexception: no connection available service operation: userprofileinformation|globaladmin@xx.onmicrosoft.com] stackexchange.redis.connectionmultiplexer.executesyncimpl(message message, resultprocessor
1 processor, serverendpoint server) in c:\teamcity\buildagent\work\3ae0647004edff78\stackexchange.redis\stackexchange\redis\connectionmultiplexer.cs:1922 stackexchange.redis.redisbase.executesync(message message, resultprocessor1 processor, serverendpoint server) in c:\teamcity\buildagent\work\3ae0647004edff78\stackexchange.redis\stackexchange\redis\redisbase.cs:80 stackexchange.redis.redisdatabase.stringget(rediskey key, commandflags flags) in c:\teamcity\buildagent\work\3ae0647004edff78\stackexchange.redis\stackexchange\redis\redisdatabase.cs:1431 xx.utils.samplestackexchangeredisextensions.get(idatabase cache, string key) in c:\proyectos\xx\xx\utils\samplestackexchangeredisextensions.cs:20
xx.cache.userprofile.getuserprofile(string identityname) in c:\proyectos\xx\xx\cache\userprofile.cs:22
x.controllers.userprofilecontroller.getpropertiesforuser() in c:\proyectos\xx\xx\controllers\userprofilecontroller.cs:16
lambda_method(closure , controllerbase , object[] ) +61
system.web.mvc.actionmethoddispatcher.execute(controllerbase controller, object[] parameters) +14
and code
public static models.userprofile getuserprofile(string identityname) { /// needs cached every user because every user can have different modules enabled. var cachekeyname = "userprofileinformation|" + identityname; idatabase cache = cacheconnectionhelper.connection.getdatabase(); models.userprofile userprofile = new models.userprofile(); object obj = cache.get(cachekeyname); string userprofilestring; if (obj != null) { //get string cache userprofilestring = obj.tostring(); //conver string our object userprofile = jsonconvert.deserializeobject<models.userprofile>(userprofilestring); return userprofile; } else { #region user profile ad uri serviceroot = new uri(settingshelper.azureadgraphapiendpoint); var token = apptoken.getapptoken(); activedirectoryclient adclient = new activedirectoryclient( serviceroot, async () => await apptoken.getapptokenasync()); string userobjectid = claimsprincipal.current.findfirst("http://schemas.microsoft.com/identity/claims/objectidentifier").value; microsoft.azure.activedirectory.graphclient.application app = (microsoft.azure.activedirectory.graphclient.application)adclient.applications.where( => a.appid == settingshelper.clientid).executesingleasync().result; if (app == null) { throw new applicationexception("unable reference application in azure ad."); } string requesturl = string.format("https://graph.windows.net/{0}/users/{1}?api-version=1.5", settingshelper.tenant, identityname); httpclient hc = new httpclient(); hc.defaultrequestheaders.authorization = new system.net.http.headers.authenticationheadervalue("bearer", token); httpresponsemessage hrm = hc.getasync(new uri(requesturl)).result; if (hrm.issuccessstatuscode) { models.userprofile currentuserprofile = jsonconvert.deserializeobject<models.userprofile>(hrm.content.readasstringasync().result); //convert object json string userprofilestring = jsonconvert.serializeobject(currentuserprofile); cache.set(cachekeyname, userprofilestring, timespan.fromminutes(settingshelper.cacheuserprofileminutes)); return currentuserprofile; } else { return null; } #endregion } } public static class samplestackexchangeredisextensions { public static t get<t>(this idatabase cache, string key) { return deserialize<t>(cache.stringget(key)); } public static object get(this idatabase cache, string key) { return deserialize<object>(cache.stringget(key)); } public static void set(this idatabase cache, string key, object value, timespan expiration) { cache.stringset(key, serialize(value), expiration); } static byte[] serialize(object o) { if (o == null) { return null; } binaryformatter binaryformatter = new binaryformatter(); using (memorystream memorystream = new memorystream()) { binaryformatter.serialize(memorystream, o); byte[] objectdataasstream = memorystream.toarray(); return objectdataasstream; } } static t deserialize<t>(byte[] stream) { binaryformatter binaryformatter = new binaryformatter(); if (stream == null) return default(t); using (memorystream memorystream = new memorystream(stream)) { t result = (t)binaryformatter.deserialize(memorystream); return result; } } questions are: 1. how can control connection exception 1 shown, user doesnt error , instead goes db if redis unavailable? 2. there anyway retry transient fault handling azure redis cache?
i believe these transient errors. have seen many of these in application logs before implemented simple retry logic. had quite few timeouts. simple retry logic, plus adding synctimeout=3000 redis connection string resolved all these me.
public object get(string key) { return deserialize(cache.stringget(key)); } public object getwithretry(string key, int wait, int retrycount) { int = 0; { try { return get(key); } catch (exception) { if (i < retrycount + 1) { thread.sleep(wait); i++; } else throw; } } while (i < retrycount + 1); return null; }
Comments
Post a Comment