public LanguageExt.Unit SetData(long time, SessionId sessionId, string key, object value) { var added = false; Sync.SetData(sessionId, key, value, time); cluster.Iter(c => { added = c.HashFieldAddOrUpdateIfKeyExists(SessionKey(sessionId), key, SessionDataItemDTO.Create(value)); if (added && key == SupplementarySessionId.Key && value is SupplementarySessionId supp) { SupplementarySessionManager.setSuppSessionInSuppMap(c, sessionId, supp); } }); return(added ? cluster.Iter(c => c.PublishToChannel(SessionsNotify, SessionAction.SetData( time, sessionId, key, value, system, nodeName))) : unit); }
public LanguageExt.Unit ClearData(long time, SessionId sessionId, string key) { Sync.ClearData(sessionId, key, time); cluster.Iter(c => c.DeleteHashField(SessionKey(sessionId), key)); return(cluster.Iter(c => c.PublishToChannel( SessionsNotify, SessionAction.ClearData(time, sessionId, key, system, nodeName)))); }
public LanguageExt.Unit Stop(SessionId sessionId) { Sync.Stop(sessionId); cluster.Iter(c => { c.Delete(SessionKey(sessionId)); SupplementarySessionManager.removeSessionIdFromSuppMap(c, sessionId); }); return(cluster.Iter(c => c.PublishToChannel(SessionsNotify, SessionAction.Stop(sessionId, system, nodeName)))); }
public SessionManager(Option <ICluster> cluster, SystemName system, ProcessName nodeName, VectorConflictStrategy strategy) { this.cluster = cluster; this.system = system; this.nodeName = nodeName; Sync = new SessionSync(system, nodeName, strategy); cluster.Iter(c => { notify = c.SubscribeToChannel <SessionAction>(SessionsNotify).Subscribe(act => Sync.Incoming(act)); var now = DateTime.UtcNow; // Look for stranded sessions that haven't been removed properly. This is done once only // on startup because the systems should be shutting down sessions on their own. This just // catches the situation where an app-domain died without shutting down properly. c.GetAllHashFieldsInBatch(c.QuerySessionKeys().ToSeq()) .Map(sessions => sessions.Filter(vals => (from ts in vals.Find(LastAccessKey).Map(v => new DateTime((long)v)) from to in vals.Find(TimeoutKey).Map(v => (long)v) where ts < now.AddSeconds(-to * 2) select true).IfNone(false)) .Keys) .Map(Seq) .Do(strandedSessions => SupplementarySessionManager.removeSessionIdFromSuppMap(c, strandedSessions.Map(ReverseSessionKey))) .Do(strandedSessions => c.DeleteMany(strandedSessions)) .Map(strandedSessions => strandedSessions.Iter(sessionId => c.PublishToChannel(SessionsNotify, SessionAction.Stop(sessionId, system, nodeName))));; // Remove session keys when an in-memory session ends ended = SessionEnded.Subscribe(sid => Stop(sid)); touch = Sync.Touched.Subscribe(tup => { try { //check if the session has not been stopped in the meantime or expired if (c.HashFieldAddOrUpdateIfKeyExists(SessionKey(tup.Item1), LastAccessKey, DateTime.UtcNow.Ticks)) { c.PublishToChannel(SessionsNotify, SessionAction.Touch(tup.Item1, system, nodeName)); } } catch (Exception e) { logErr(e); } }); }); }
public int Incoming(SessionAction incoming) { if (incoming.SystemName == system.Value && incoming.NodeName == nodeName.Value) { return(0); } switch (incoming.Tag) { case SessionActionTag.Touch: Touch(incoming.SessionId); break; case SessionActionTag.Start: Start(incoming.SessionId, incoming.Timeout, Map <string, object>()); break; case SessionActionTag.Stop: Stop(incoming.SessionId); break; case SessionActionTag.SetData: var type = Type.GetType(incoming.Type); if (type == null) { logErr("Session-value type not found: " + incoming.Type); } else { var value = Deserialise.Object(incoming.Value, type); if (value == null) { logErr("Session-value is null or failed to deserialise: " + incoming.Value); } else { SetData(incoming.SessionId, incoming.Key, value, incoming.Time); } } break; case SessionActionTag.ClearData: ClearData(incoming.SessionId, incoming.Key, incoming.Time); break; default: return(0); } return(1); }
public LanguageExt.Unit SetData(long time, SessionId sessionId, string key, object value) { Sync.SetData(sessionId, key, value, time); cluster.Iter(c => c.HashFieldAddOrUpdate(SessionKey(sessionId), key, SessionDataItemDTO.Create(value))); return(cluster.Iter(c => c.PublishToChannel(SessionsNotify, SessionAction.SetData( time, sessionId, key, value, system, nodeName )))); }
public LanguageExt.Unit SetData(long time, SessionId sessionId, string key, object value) { Sync.SetData(sessionId, key, value, time); cluster.Iter(c => c.HashFieldAddOrUpdate(SessionKey(sessionId), key, value)); return(cluster.Iter(c => c.PublishToChannel(SessionsNotify, SessionAction.SetData( time, sessionId, key, JsonConvert.SerializeObject(value, ActorSystemConfig.Default.JsonSerializerSettings), system, nodeName )))); }
public LanguageExt.Unit ClearData(long time, SessionId sessionId, string key) { Sync.ClearData(sessionId, key, time); cluster.Iter(c => { c.DeleteHashField(SessionKey(sessionId), key); if (key == SupplementarySessionId.Key) { SupplementarySessionManager.removeSessionIdFromSuppMap(c, sessionId); } }); return(cluster.Iter(c => c.PublishToChannel( SessionsNotify, SessionAction.ClearData(time, sessionId, key, system, nodeName)))); }
public SessionManager(Option <ICluster> cluster, SystemName system, ProcessName nodeName, VectorConflictStrategy strategy) { this.cluster = cluster; this.system = system; this.nodeName = nodeName; Sync = new SessionSync(system, nodeName, strategy); cluster.Iter(c => { notify = c.SubscribeToChannel <SessionAction>(SessionsNotify).Subscribe(act => Sync.Incoming(act)); var now = DateTime.UtcNow; // Look for stranded sessions that haven't been removed properly. This is done once only // on startup because the systems should be shutting down sessions on their own. This just // catches the situation where an app-domain died without shutting down properly. c.QuerySessionKeys() .Map(key => from ts in c.GetHashField <long>(key, LastAccessKey) from to in c.GetHashField <int>(key, TimeoutKey) where new DateTime(ts) < now.AddSeconds(-to * 2) // Multiply by 2, just to catch genuine non-active sessions select c.Delete(key)) .Iter(id => { }); // Remove session keys when an in-memory session ends ended = SessionEnded.Subscribe(sid => Stop(sid)); touch = Sync.Touched.Subscribe(tup => { try { c.HashFieldAddOrUpdate(SessionKey(tup.Item1), LastAccessKey, DateTime.UtcNow.Ticks); c.PublishToChannel(SessionsNotify, SessionAction.Touch(tup.Item1, system, nodeName)); } catch (Exception e) { logErr(e); } }); }); }
public int Incoming(SessionAction incoming) { if (incoming.SystemName == system.Value && incoming.NodeName == nodeName.Value) { return(0); } switch (incoming.Tag) { case SessionActionTag.Touch: Touch(incoming.SessionId); break; case SessionActionTag.Start: Start(incoming.SessionId, incoming.Timeout, Map <string, object>()); break; case SessionActionTag.Stop: Stop(incoming.SessionId); break; case SessionActionTag.SetData: SessionDataTypeResolve.TryDeserialise(incoming.Value, incoming.Type) .Map(o => SetData(incoming.SessionId, incoming.Key, o, incoming.Time)) .IfLeft(SessionDataTypeResolve.DeserialiseFailed(incoming.Value, incoming.Type)); break; case SessionActionTag.ClearData: ClearData(incoming.SessionId, incoming.Key, incoming.Time); break; default: return(0); } return(1); }
public LanguageExt.Unit Start(SessionId sessionId, int timeoutSeconds) { Sync.Start(sessionId, timeoutSeconds); cluster.Iter(c => c.HashFieldAddOrUpdate(SessionKey(sessionId), TimeoutKey, timeoutSeconds)); return(cluster.Iter(c => c.PublishToChannel(SessionsNotify, SessionAction.Start(sessionId, timeoutSeconds, system, nodeName)))); }
public LanguageExt.Unit Stop(SessionId sessionId) { Sync.Stop(sessionId); cluster.Iter(c => c.Delete(SessionKey(sessionId))); return(cluster.Iter(c => c.PublishToChannel(SessionsNotify, SessionAction.Stop(sessionId, system, nodeName)))); }