• Version 1.15.2
Show / Hide Table of Contents

Session Scheduler Sample

Source code


using System;
using OnixS.Fix;
using OnixS.Fix.Scheduling;

namespace SessionScheduler
{
    /// <summary>
    /// This sample demonstrates the use of scheduling services and the ability to define session sequence number reset policy.
    /// </summary>
    sealed class Sample : IDisposable
    {
        private Scheduler scheduler;

        private Session acceptor;
        private Session initiator;

        public Sample()
        {
            ConstructScheduler();
            ConstructSessions();
        }

        private void ConstructSessions()
        {
            const string AcceptorId = "Acceptor";
            const string InitiatorId = "Initiator";
            const ProtocolVersion protocolVersion = ProtocolVersion.Fix44;
            const bool seqNumberLogonPolicy = true;

            acceptor = new Session(AcceptorId, InitiatorId, protocolVersion, seqNumberLogonPolicy, SessionStorageType.FileBasedStorage);

            acceptor.Error += (sender, args) =>
            {
                Log("Session Error: " + args.ToString());
            };

            acceptor.Warning += (sender, args) =>
            {
                Log("Session Warning: " + args.ToString());
            };

            initiator = new Session(InitiatorId, AcceptorId, protocolVersion, seqNumberLogonPolicy, SessionStorageType.FileBasedStorage);

            initiator.Error += (sender, args) =>
            {
                Log("Session Error: " + args.ToString());
            };

            initiator.Warning += (sender, args) =>
            {
                Log("Session Warning: " + args.ToString());
            };

            // The sample schedules the session - initiator, so its state will be traced to make sure the scheduler works.

            initiator.StateChanged += (sender, args) =>
            {
                Console.WriteLine($"{DateTime.Now.ToLongTimeString()}: Session {sender} changed its state from {args.PrevState} to {args.NewState}.");
            };
        }

        private void ConstructScheduler()
        {
            const string ConfigFile = "Scheduler.config";
            scheduler = new Scheduler(ConfigFile);

            scheduler.Error += (object scheduler, OnixS.Fix.Scheduling.SessionErrorEventArgs args) => {
                Log($"Scheduler reported error for session {args.Session}: {args.Reason}");
            };
        }

        ~Sample()
        {
            CleanUp();
        }

        public void Dispose()
        {
            CleanUp();
            GC.SuppressFinalize(this);
        }

        private void CleanUp()
        {
            scheduler.Dispose();

            initiator.Dispose();
            acceptor.Dispose();
        }

        public void Run()
        {
            // The acceptor is maintained manually. So the reset of sequence numbers must be done manually before logon.
            acceptor.ResetLocalSequenceNumbers();

            // Comment this call if you want to check how scheduler notifies about errors.
            acceptor.LogonAsAcceptor();

            SessionSchedule scheduleForInitiator = ConstructShortTimeActivitySchedule();

            scheduler.Register(initiator, scheduleForInitiator, scheduler.ConnectionSettings["LocalInitiator"]);

            Log($"{initiator} is scheduled for automatic connection.");

            // After the construction, the session is in a disconnected state, so we cannot wait for logout.
            // Instead, we have to give time to the scheduler to activate the session.
            // Let's wait till the scheduled logout time.
            PauseUntil(scheduleForInitiator.LogoutTimes[(int)DateTime.Now.DayOfWeek]);

            // Make sure that the initiator is shutdown.
            WaitUntilLogout(initiator);

            // Once the initiator disconnects from the acceptor, the acceptor starts waiting for the next login.
            // So we have to logout the acceptor manually.
            acceptor.Logout();
            WaitUntilLogout(acceptor);
        }

        private static SessionSchedule ConstructShortTimeActivitySchedule()
        {
            const int LogonDelayInSeconds = 5;
            Log($"LogonDelayInSeconds={LogonDelayInSeconds}");

            TimeSpan logonTime = DateTime.Now.TimeOfDay.Add(new TimeSpan(0, 0, LogonDelayInSeconds));

            const int SessionDurationInSeconds = 10;
            Log($"SessionDurationInSeconds={SessionDurationInSeconds}");
            TimeSpan logoutTime = logonTime.Add(new TimeSpan(0, 0, SessionDurationInSeconds));

            return new SessionSchedule(
                DayOfWeek.Sunday,
                DayOfWeek.Saturday,
                logonTime,
                logoutTime,
                SessionDuration.Day,
                SequenceNumberResetPolicy.Daily);
        }

        private static void PauseUntil(TimeSpan timeOfDay)
        {
            System.Threading.Thread.Sleep(timeOfDay.Subtract(DateTime.Now.TimeOfDay));
        }

        private static void WaitUntilLogout(Session session)
        {
            while (session.State != SessionState.Disconnected)
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
        }

        private static void Log(string msg)
        {
            Console.Out.WriteLine($"{DateTime.Now.ToLongTimeString()}: {msg}");
        }
    }
}

In this article
Back to top Copyright © Onix Solutions.
Generated by DocFX