예제 #1
0
        /// <summary>
        /// Return data from the local database
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private async Task <List <EconomicRelease> > FillLocalRequest(EconomicReleaseRequest request)
        {
            using (var context = new MyDBContext())
            {
                //this wrangling is necessary because MySql doesn't support TruncateTime()
                //if a time is set, use it as the limit; if not, we want all events from that day
                var toDate = request.ToDate.TimeOfDay.TotalSeconds == 0
                    ? request.ToDate.AddDays(1)
                    : request.ToDate;

                var queryableData = context.EconomicReleases
                                    .Where(x =>
                                           x.DateTime >= request.FromDate &&
                                           x.DateTime <= toDate);

                if (request.Filter != null)
                {
                    queryableData = queryableData.Where(request.Filter);
                }

                try
                {
                    var result = await queryableData.ToListAsync().ConfigureAwait(false);

                    _logger.Info($"ERB returning {result.Count} items from the local db");
                    return(result);
                }
                catch (Exception ex)
                {
                    //A malformed filter can cause an exception when querying the db
                    _logger.Error(ex, "ERB: error when querying database - " + ex.Message);
                    return(new List <EconomicRelease>());
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Called by the <see cref="T:Quartz.IScheduler"/> when a <see cref="T:Quartz.ITrigger"/>
        ///             fires that is associated with the <see cref="T:Quartz.IJob"/>.
        /// </summary>
        /// <remarks>
        /// The implementation may wish to set a  result object on the
        ///             JobExecutionContext before this method exits.  The result itself
        ///             is meaningless to Quartz, but may be informative to
        ///             <see cref="T:Quartz.IJobListener"/>s or
        ///             <see cref="T:Quartz.ITriggerListener"/>s that are watching the job's
        ///             execution.
        /// </remarks>
        /// <param name="context">The execution context.</param>
        public void Execute(IJobExecutionContext context)
        {
            _logger = LogManager.GetCurrentClassLogger();

            JobDataMap dataMap = context.JobDetail.JobDataMap;
            EconomicReleaseUpdateJobSettings settings;

            try
            {
                settings = JsonConvert.DeserializeObject <EconomicReleaseUpdateJobSettings>((string)dataMap["settings"]);
            }
            catch (Exception e)
            {
                _logger.Error(e, "Failed to deserialize data update job settings");
                return;
            }

            _logger.Info($"Data Update job {settings.Name} triggered.");

            _broker.Error += _broker_Error;

            var startDate = DateTime.Now.AddBusinessDays(-settings.BusinessDaysBack);
            var endDate   = DateTime.Now.AddBusinessDays(settings.BusinessDaysAhead);
            var req       = new EconomicReleaseRequest(startDate, endDate, dataLocation: DataLocation.ExternalOnly, dataSource: settings.DataSource);
            var releases  = _broker.RequestEconomicReleases(req).Result; //no async support in Quartz, and no need for it anyway, this runs on its own thread

            _logger.Trace($"Economic release update job downloaded {releases.Count} items");

            JobComplete();
        }
예제 #3
0
        /// <summary>
        /// Called by the <see cref="T:Quartz.IScheduler"/> when a <see cref="T:Quartz.ITrigger"/>
        ///             fires that is associated with the <see cref="T:Quartz.IJob"/>.
        /// </summary>
        /// <remarks>
        /// The implementation may wish to set a  result object on the
        ///             JobExecutionContext before this method exits.  The result itself
        ///             is meaningless to Quartz, but may be informative to
        ///             <see cref="T:Quartz.IJobListener"/>s or
        ///             <see cref="T:Quartz.ITriggerListener"/>s that are watching the job's
        ///             execution.
        /// </remarks>
        /// <param name="context">The execution context.</param>
        public void Execute(IJobExecutionContext context)
        {
            _logger = LogManager.GetCurrentClassLogger();

            JobDataMap dataMap = context.JobDetail.JobDataMap;
            EconomicReleaseUpdateJobSettings settings;
            try
            {
                settings = JsonConvert.DeserializeObject<EconomicReleaseUpdateJobSettings>((string)dataMap["settings"]);
            }
            catch (Exception e)
            {
                _logger.Error(e, "Failed to deserialize data update job settings");
                return;
            }

            _logger.Info($"Data Update job {settings.Name} triggered.");

            _broker.Error += _broker_Error;

            var startDate = DateTime.Now.AddBusinessDays(-settings.BusinessDaysBack);
            var endDate = DateTime.Now.AddBusinessDays(settings.BusinessDaysAhead);
            var req = new EconomicReleaseRequest(startDate, endDate, dataLocation: DataLocation.ExternalOnly, dataSource: settings.DataSource);
            var releases = _broker.RequestEconomicReleases(req).Result; //no async support in Quartz, and no need for it anyway, this runs on its own thread
            _logger.Trace($"Economic release update job downloaded {releases.Count} items");

            JobComplete();
        }
예제 #4
0
        public void RequestDirectedToSpecifiedDatasource()
        {
            var req = new EconomicReleaseRequest(DateTime.Now, DataLocation.ExternalOnly, dataSource: _source1.Object.Name);
            var res = _broker.RequestEconomicReleases(req).Result;

            _source1.Verify(x => x.RequestData(It.IsAny <DateTime>(), It.IsAny <DateTime>()));
        }
예제 #5
0
        public void RequestDirectedToDefaultDataSourceIfNotSpecified()
        {
            var req = new EconomicReleaseRequest(DateTime.Now, DataLocation.ExternalOnly, dataSource: null);
            var res = _broker.RequestEconomicReleases(req).Result;

            _source2.Verify(x => x.RequestData(It.IsAny <DateTime>(), It.IsAny <DateTime>()));
        }
예제 #6
0
 /// <summary>
 /// Returns the appropriate external datasource for the give request
 /// </summary>
 /// <param name="request"></param>
 /// <returns></returns>
 private IEconomicReleaseSource GetClient(EconomicReleaseRequest request)
 {
     if (!string.IsNullOrEmpty(request.DataSource))
     {
         return(DataSources.ContainsKey(request.DataSource) ? DataSources[request.DataSource] : null);
     }
     else
     {
         return(DataSources[_defaultDataSource]);
     }
 }
예제 #7
0
        public async Task <List <EconomicRelease> > RequestEconomicReleases(EconomicReleaseRequest request)
        {
            _logger.Info($"ERB: filling request from {request.FromDate:yyyyMMdd} to {request.ToDate:yyyyMMdd} from {request.DataSource ?? "default"} ({request.DataLocation})");

            if (request.DataLocation == DataLocation.LocalOnly)
            {
                return(await FillLocalRequest(request).ConfigureAwait(false));
            }

            //What if it's DataLocation.Both? Doesn't really make sense to grab half and half
            //old data is updated with the "actual" value of the release, so we just re-grab everything externally

            //get data externally
            return(await FillExternalRequest(request).ConfigureAwait(false));
        }
예제 #8
0
        public void ExternalResultsReturnedCorrectly()
        {
            var data = new List <EconomicRelease>
            {
                new EconomicRelease("1", "US", "USD", DateTime.Now, Importance.Low, null, null, null),
            };

            _source2
            .Setup(x => x.RequestData(It.IsAny <DateTime>(), It.IsAny <DateTime>()))
            .ReturnsAsync(data);

            var req = new EconomicReleaseRequest(DateTime.Now, DataLocation.ExternalOnly);
            var res = _broker.RequestEconomicReleases(req).Result;

            CollectionAssert.AreEquivalent(data, res);
        }
예제 #9
0
        /// <summary>
        /// Forward the request to the appropriate external data source
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private async Task <List <EconomicRelease> > FillExternalRequest(EconomicReleaseRequest request)
        {
            var client = GetClient(request);

            if (client == null)
            {
                _logger.Error($"ERB: Could not find specified data source {request.DataSource}");
                RaiseEvent(Error, this, new ErrorArgs(-1, $"ERB: Could not find specified data source {request.DataSource}"));
                return(new List <EconomicRelease>());
            }

            var data = await client.RequestData(request.FromDate, request.ToDate).ConfigureAwait(false);

            //save the data we got
            try
            {
                using (var context = new MyDBContext())
                {
                    var dbSet = context.Set <EconomicRelease>();
                    foreach (var release in data)
                    {
                        //the data we get might be a duplicate and we want the latest values of everything, so we can't just insert
                        dbSet.AddOrUpdate(x => new { x.Name, x.Country, x.DateTime }, release);
                    }
                    context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "ERB: Could not save data");
            }

            //Filter the data if necessary
            if (request.Filter != null)
            {
                data = data.AsQueryable().Where(request.Filter).ToList();
            }

            _logger.Info($"ERB returning {data?.Count} items from {client.Name}");

            return(data);
        }
예제 #10
0
        public void RequestFilterIsApplied()
        {
            var data = new List <EconomicRelease>
            {
                new EconomicRelease("1", "US", "USD", DateTime.Now, Importance.Low, null, null, null),
                new EconomicRelease("2", "UK", "GBP", DateTime.Now, Importance.High, null, null, null),
                new EconomicRelease("3", "CN", "RMB", DateTime.Now, Importance.High, null, null, null),
                new EconomicRelease("4", "EU", "EUR", DateTime.Now, Importance.None, null, null, null),
                new EconomicRelease("5", "US", "USD", DateTime.Now, Importance.Mid, null, null, null),
                new EconomicRelease("6", "US", "USD", DateTime.Now, Importance.High, null, null, null),
            };

            _source2
            .Setup(x => x.RequestData(It.IsAny <DateTime>(), It.IsAny <DateTime>()))
            .ReturnsAsync(data);

            var req = new EconomicReleaseRequest(DateTime.Now, DataLocation.ExternalOnly, x => x.Importance >= Importance.Mid && x.Currency == "USD");
            var res = _broker.RequestEconomicReleases(req).Result;

            CollectionAssert.AreEquivalent(data.AsQueryable().Where(req.Filter).ToList(), res);
        }
예제 #11
0
 /// <summary>
 /// Get economic releases
 /// </summary>
 public async Task <ApiResponse <List <EconomicRelease> > > GetEconomicReleases(EconomicReleaseRequest req) =>
 await _apiClient.GetAsync <List <EconomicRelease> >("/economicreleases", req).ConfigureAwait(false);