public RavenRemoteQueueTransporter(RavenFactory ravenFactory, string endpointName, string processIdentity)
 {
     _ravenFactory    = ravenFactory;
     _endpointName    = endpointName;
     _processIdentity = processIdentity;
     _tokenSource     = new CancellationTokenSource();
 }
        void Work(RavenTransportMessage message)
        {
            var transportMessage = new TransportMessage(message.Id, message.Headers);

            transportMessage.Body          = message.Body;
            transportMessage.MessageIntent = message.MessageIntent;

            using (var session = RavenFactory.StartSession(transportMessage.Id))
            {
                Exception exception = null;

                try
                {
                    _tryProcessMessage(transportMessage);
                }
                catch (Exception e)
                {
                    exception = e;
                }
                finally
                {
                    RavenFactory.EndSession(transportMessage.Id);
                }

                _endProcessMessage(transportMessage, exception);

                session.Store(message); //attach message to session
                session.Delete(message);
                //message.Destination = "trash";
                session.SaveChanges();
                //session.Advanced.DocumentStore.DatabaseCommands.ForDatabase((session as DocumentSession).DatabaseName).Delete(message.Id, null);
            }
        }
        public void Send(TransportMessage message, SendOptions sendOptions)
        {
            var counter = DateTime.UtcNow.Ticks;
            var ravenTransportMessage = new RavenTransportMessage(message, sendOptions, counter);

            //push all outbound messages to the endpoint db
            RavenFactory.UsingSession(message.CorrelationId, session => session.Store(ravenTransportMessage));
        }
        void Lead()
        {
            using (var session = RavenFactory.OpenSession())
            {
                session.Advanced.UseOptimisticConcurrency = true;

                var l = session.Advanced.Lazily.Load <Leadership>(Leadership.Identifier);
                var f = session.Advanced.Lazily.LoadStartingWith <Followership>(Followership.IdPrefix);
                session.Advanced.Eagerly.ExecuteAllPendingLazyOperations();

                var leadership = l.Value;

                var followers = f.Value.ToList();
                var me        = followers.FirstOrDefault(x => x.FollowerId == ProcessIdentity);
                if (me == null)
                {
                    return;
                }

                if (me.ConsideringCoup)
                {
                    if (leadership == null)
                    {
                        leadership = new Leadership();
                        session.Store(leadership);
                    }

                    if (leadership.IsHumbleFollower(ProcessIdentity))
                    {
                        leadership.UsurpPower(ProcessIdentity);
                        session.SaveChanges(); //throw if someone else beats me
                        //TODO: Log Won Election!
                    }
                }

                if (leadership == null)
                {
                    return;
                }
                if (leadership.IsHumbleFollower(ProcessIdentity))
                {
                    return;
                }

                leadership.CommandFollowers(followers);

                var dead = followers.Where(leadership.IsDeadFollower).ToList();
                dead.ForEach(session.Delete);

                session.SaveChanges();
                Console.WriteLine("counts... {0}, {1}", _workQueue.Count, InProgress.Count);
            }
        }
        public void CreateQueueIfNecessary(Address address, string account)
        {
            if (address.Queue.StartsWith(EndpointName) && address.Queue != EndpointName)
            {
                return;                                                                          //combine all queues for an endpoint in one db
            }
            var store = RavenFactory
                        .FindDocumentStore(address.Queue);

            store
            .DatabaseCommands.GlobalAdmin
            .EnsureDatabaseExists(address.Queue);

            var commands = store.DatabaseCommands.ForDatabase(address.Queue);

            new RavenTransportMessageIndex().Execute(commands, store.Conventions);

            //todo: log that we are creating db
        }
        void Follow()
        {
            using (var session = RavenFactory.OpenSession())
            {
                var l = session.Advanced.Lazily.Load <Leadership>(Leadership.Identifier);
                var m = session.Advanced.Lazily.Load <Followership>(Followership.FormatId(ProcessIdentity));
                session.Advanced.Eagerly.ExecuteAllPendingLazyOperations();

                var leadership = l.Value ?? new Leadership();
                var me         = m.Value;

                if (me == null)
                {
                    me = new Followership(ProcessIdentity);
                    session.Store(me);
                }

                if (leadership.Status == Leadership.ClusterStatus.Turmoil ||
                    leadership.DeniedAssignment(ProcessIdentity))
                {
                    while (_workQueue.Count > 0)
                    {
                        RavenTransportMessage trash;
                        _workQueue.TryTake(out trash); //clear the queue
                    }

                    Thread.Sleep(10);       //make sure workers have enough time to get their work in the InProgress collection
                    RecentMessages.Clear(); //we're clearing the decks, so forget what we've seen and rely on db
                }

                if (RecentMessages.Count == 0)
                {
                    me.LastSequenceNumber = 0;
                }

                if (leadership.Status == Leadership.ClusterStatus.Harmony &&
                    leadership.HasAssignment(ProcessIdentity))
                {
                    var assignment = leadership.GetAssignment(ProcessIdentity);

                    var take = MaxMessagesToRead - _workQueue.Count;

                    RavenQueryStatistics stats = null;

                    var messages =
                        session.Query <RavenTransportMessage, RavenTransportMessageIndex>()
                        .Statistics(out stats)
                        .Where(x => x.Destination == _address.Queue)
                        .Where(x => x.ClaimTicket >= assignment.LowerBound && x.ClaimTicket <= assignment.UpperBound)
                        .Where(x => x.SequenceNumber >= me.LastSequenceNumber)
                        .OrderBy(x => x.SequenceNumber)
                        .Take(take)
                        .ToList();

                    Console.WriteLine("Follower Query Stats: {0:N0}", stats.DurationMilliseconds);

                    messages = messages.Where(x => !RecentMessages.Contains(x.Id)).ToList();
                    messages.ForEach(_workQueue.Add);
                    messages.Select(x => x.Id).ToList().ForEach(RecentMessages.Enqueue);

                    if (messages.Any())
                    {
                        me.LastSequenceNumber = messages.Last().SequenceNumber;
                    }
                }

                var progress = InProgress.Select(x => x.Value).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
                me.MakeReportForLeader(leadership, progress);
                session.SaveChanges();
            }
        }