public virtual async Task Track( string eventName, ActivityTimeframe timeframe, DateTime timestamp, bool publishable, params long[] users) { Validation.ValidateEventName(eventName); Validation.ValidateUsers(users); var eventsKey = GenerateKey(); var publishedEventsKey = eventsKey + Settings.KeySeparator + "published"; string channel = null; byte[] payload = null; if (publishable) { channel = eventsKey + Settings.KeySeparator + eventName.ToUpperInvariant(); payload = new UserActivitySubscriptionInfo { EventName = eventName, Timestamp = timestamp, Timeframe = timeframe, Users = users }.Serialize(); } var timeframeKeys = GenerateEventTimeframeKeys( eventName, timeframe, timestamp).ToList(); var db = Settings.Db; using (var connection = await ConnectionFactories.Open()) { var eventTasks = new List <Task> { connection.Sets.Add(db, eventsKey, eventName), connection.Sets.Add( db, eventsKey + Settings.KeySeparator + eventName, timeframe.ToString()) }; if (publishable) { eventTasks.Add( connection.Sets.Add( db, publishedEventsKey, eventName)); } await Task.WhenAll(eventTasks); var bitTasks = new List <Task>(); foreach (var timeframeKey in timeframeKeys) { bitTasks.AddRange(users.Select(user => connection.Strings.SetBit( db, timeframeKey, user, true))); } await Task.WhenAll(bitTasks); if (publishable) { await connection.Publish(channel, payload); } } }