locked
Timer to schedule tasks to monitor files in different folders RRS feed

  • Question

  • Hello experts

    I want to monitor files in different folders using timer to schedule tasks at different times within worker service in c#. I have got the idea working if I hard code two interfaces but if I want to do it for multiple tasks how will i run my monitorFiles function to do that using the Task.delay.

    the code is following:

    Thanks in advance

    *************************IntrfaceMetaData.cs : to hold information about each interface

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace OASFileMonitor
    {
        public class InterfaceMetaData
        {
            public DateTime LastRanAt { get; set; }
            public InterfaceConfiguration Configuration { get; set; }

            public InterfaceMetaData(InterfaceConfiguration config) 
            {
                this.Configuration = config;       
            }
        }
    }

    ***************************the InterfaceConfigurations: to hold all configurations that are saved in the json file

    using Cronos;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;

    namespace OASFileMonitor
    {
        public class InterfaceConfigurations
        {
           // public int Config_id { get; set; }
            public List<InterfaceConfiguration> Configurations { get; set; }
        }
        public class InterfaceConfiguration
        {
            public string Interface_id { get; set; }
            public string Source { get; set; } 
            public string Destination { get; set; }
            public string Description { get; set; }
            public CronExpression Runat { get; set; }
           // public string Timeout { get; set; }
            public Regex Regx { get; set; }
        }

        //public class TimerScheduleClass
        //{
        //    public CronExpression Schedule { get; set;}
        //}

        //public class RegxType
        //{
        //    public Regex regx { get; set; }
        //}
    }

    **********************the Config.json

    {
      "configurations": [
        {
          "Interface_id": 1,
          "Source": "C:\\Users\\Sehammohamed\\SubFolderA\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderB\\",
          "Description": "Monitoring files between folder 1",
          "TimerFireEveryDayAt12PM": {
            "Schedule_at": "50 12 * * *" //every 12.50 PM daily
          }, //every 12.50 PM daily 
          "Interval": 180000, //every 3 mins (3 * 60000)
          "Regx": {
            "Pattern": "^.*\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        },
        {
          "Interface_id": 2,
          "Source": "C:\\Users\\Sehammohamed\\SubFolderC\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderD\\",
          "Description": "Monitoring files between folder 2",
          "Interval": 180000, //every five mins
          "TimerFireEveryDayAt12PM": {
            "Schedule_at": "50 12 * * *" //every 12.50 PM daily
          },
          "Regx": {
            "Pattern": "^.*\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        }
      ]
    }
    /* "TimerFireAtTheGivenTime": {
            "Schedule": "0 5 * * * *"
           },*/

    *************************Worker.cs class // how will call or fit the MonitorAndProcessFiles with the Task.delay or how can use it withing the RuntInterface method to monitor files based on the passed interface_id passed from the interface meta data.

    Any help will be really really appreicated.

    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    namespace OASFileMonitor
    {
        public class Worker : BackgroundService
        {
            private readonly ILogger<Worker> _logger;
            
            public static List<InterfaceConfiguration> _ics = new List<InterfaceConfiguration>();
            public static Dictionary<string, InterfaceMetaData> _imds = new Dictionary<string, InterfaceMetaData>();

            private string conf = @"C:\Temp\Config.json";

            private long counter = 0;

            public Worker(ILogger<Worker> logger)
            {
                _logger = logger;
            }

            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {

                _logger.LogInformation("OAS FileMonitor started ...");

                try
                {

                    _logger.LogInformation("Reading configuration ...");

                    _ics = 
                        (JsonConvert.DeserializeObject<InterfaceConfigurations>(
                            File.ReadAllText(conf)
                         )
                        ).Configurations;
                }
                catch (Exception ex)
                {
                    _logger.LogCritical("Error reading configuration file: " + conf);
                    _logger.LogCritical(ex.Message);
                    return;
                }

                while (!stoppingToken.IsCancellationRequested)
                {

                    counter++; // increment a counter so we can fire the interfaces every x seconds

                    foreach (InterfaceConfiguration ic in _ics)
                    {
                    
                        // Check interface here...
                        // For the purposes of getting to the meat of things we'll assume every interface runs every 5 seconds
                        if ((counter % 7 == 0 && ic.Interface_id == "1") || (counter % 11 == 0 && ic.Interface_id == "2"))
                        {

                            // Do we already have the interface's information in the meta-data list?
                            if (!_imds.ContainsKey(ic.Interface_id))
                            {
                                _imds.Add(ic.Interface_id, new InterfaceMetaData(ic));
                            }
                            else
                            {
                                _logger.LogInformation(string.Format("Interface {1} last ran at: {0}", _imds[ic.Interface_id].LastRanAt, ic.Interface_id));
                            }

                            _ = Task.Run(() => runInterface(_imds[ic.Interface_id]), CancellationToken.None);
                        }
                        
                    }

                    _logger.LogInformation(string.Format("Tick@{0}", DateTime.Now));

                    await Task.Delay(1000, stoppingToken);
                }


                async void runInterface(InterfaceMetaData IntDat)
                {

                    Console.WriteLine("Interface " + IntDat.Configuration.Interface_id + " is running !");
                    
                    await Task.Delay(IntDat.Configuration.Interface_id == "1" ? 5000 : 2000 , stoppingToken);
                    
                    IntDat.LastRanAt = DateTime.Now;

                    Console.WriteLine("Interface " + IntDat.Configuration.Interface_id + " is finished !");

                }

                private void MonitorAndProcessFiles(object sender, ElapsedEventArgs e)
                {
                    /*Check if dest directory exist, if yes then move the files */
                    try
                    {
                        for (int i = 0; i < configsItems.Count; i++)
                        {
                            if (configsItems.Count > 0)
                            {
                                rootPath = configsItems[i].Source;
                                destPath = configsItems[i].Destination;
                                regex = configsItems[i].regx;

                                bool directoryExists = Directory.Exists(destPath);

                                if (directoryExists)
                                {
                                    eventLog1.WriteEntry($"The [{rootPath}] exists.");
                                    log.Information($"The [{rootPath}] exists.");

                                    var files = Directory.GetFiles(rootPath).OrderBy(f => new FileInfo(f).CreationTime).Where(item => regex.IsMatch(item));

                                    eventLog1.WriteEntry($"Moving files from Folder: {rootPath}");
                                    log.Information($"Moving files from Folder: {rootPath}");
                                    foreach (string file in files)
                                    {
                                        try
                                        {
                                            File.SetAttributes(destPath, FileAttributes.Normal);
                                            File.Move(file, $"{destPath}{Path.GetFileName(file)} ");
                                            eventLog1.WriteEntry($"File {Path.GetFileName(file)} moved to the the {destPath} successfullly");
                                            log.Information($"File {Path.GetFileName(file)} moved to the the {destPath} successfullly");
                                        }
                                        catch (IOException)
                                        {
                                            eventLog1.WriteEntry($"Failed moving {Path.GetFileName(file)} to the {destPath}, File is being used by another process!", EventLogEntryType.Error);
                                            log.Information($"Failed moving {Path.GetFileName(file)} to the {destPath}, File is being used by another process! ");
                                        }
                                    }
                                }
                                else
                                {
                                    Directory.CreateDirectory(destPath);

                                }
                            }
                        }
                    }//end of main try block
                    catch (Exception)
                    {
                        eventLog1.WriteEntry("Can not access folders over the network", EventLogEntryType.Error);
                        log.Information("Can not access folders over the network");
                    }

                }/*End of MonitorAndProcessFiles*/
            }
        }
    }

    Saturday, October 17, 2020 8:02 AM

All replies

  • Hi Seham_1981,

    Thank you for posting here.

    Based on my research, hope the following reference could be helpful.

    How to run multiple task in background service in .net core with different timer duration

    Besides, if the reference cannot help you solve the problem, please provide more related code about 'InterfaceConfigurations', 'configsItems' and more detailed description about your question.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, October 19, 2020 6:29 AM
  • I want to check which interface from the json file to run based on the cron expression value in the config. I have used the Task.Run() and in the call back function I passed the function That will rub=n the interface, but how will pass the schedule_at or run_at from Task.Run from my config.json to the runInterface function. here are my code:

    config.json //updated.*******************

    {
      "configurations": [
        {
          "Interface_id": "1",
          "Source": "C:\\Users\\Sehammohamed\\SubFolderA\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderB\\",
          "Description": "Moving files from folder 1",
          "TimerFireAtTheGivenTime": {
            "Runat": "0 */5 * * * *" //every 5 seconds
          },
          "Schedule_from": "2020-10-18T05:30:00",
          "Regx": {
            "Pattern": "^.*\\\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        },
        {
          "Interface_id": "2",
          "Source": "C:\\Users\\Sehammohamed\\SubFolderC\\",
          "Destination": "C:\\Users\\Sehammohamed\\SubFolderD\\",
          "Description": "Moving files from folder 2",
          "TimerFireAtTheGivenTime": {
            "Runat": "0 */5 * * * * " // runs every five seconds
          },
          "Schedule_from": "2020-10-18T05:30:00",
          "Regx": {
            "Pattern": "^.*\\\\.(jpg|JPG|gif|GIF|doc|docx|DOC|pdf|PDF)$",
            "Options": 0
          }
        }
      ]
    }

    ***********************workerservice.cs*****************

                                                                                                                 

    using Cronos;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text.RegularExpressions;
    using System.Threading;
    using System.Threading.Tasks;

    namespace OASFileProcessing
    {
        public class Worker : BackgroundService
        {
            private readonly ILogger<Worker> _logger;
            public string rootPath;
            public string destPath;
            public CronExpression ranat;
            public string schedule_from;
            public Regex regx;
            DateTime startTime ;
            DateTime finishedTime;

            private Timer timer;

            public static List<InterfaceConfiguration> configs = new List<InterfaceConfiguration>();
            public static Dictionary<string, InterfaceMetaData> interfaceMetaData = new Dictionary<string, InterfaceMetaData>();

            private string jsonConfig = @"C:\Users\SehamMohamed\source\repos\WorkerServiceApp\WorkerService\Config.json";

            private long counter = 0;

            public Worker(ILogger<Worker> logger)
            {
                _logger = logger;
            }

            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                _logger.LogInformation("OAS FileMonitor started ...");
                try
                {
                    _logger.LogInformation("Reading configuration ...");

                    string json = File.ReadAllText(@"C:\TFS\OAS6\Features\OASIntegration\WorkerServiceApp\WorkerService\Config.json");
                    JObject data = JObject.Parse(json);
                    var result = data.SelectTokens("configurations[*]");
                    foreach (JToken item in result)
                    {
                        string source = item.Value<string>("Source");
                        string Destination = item.Value<string>("Destination");
                        var ranat = item.SelectToken("TimerFireAtTheGivenTime.Runat");
                        var schedule_from = item.Value<DateTime>("Schedule_from");
                        var regex = item.SelectToken("Regx.Pattern");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogCritical("Error reading configuration file: " + jsonConfig);
                    _logger.LogCritical(ex.Message);
                    return;
                }
                while (!stoppingToken.IsCancellationRequested)
                {

                    counter++; // increment a counter so we can fire the interfaces every x seconds
                    foreach (InterfaceConfiguration interfaceConfig in configs)
                    {

                        DateTime now = DateTime.Now;
                        DateTime schedule_from = interfaceConfig.Schedule_from;

                        if (now < schedule_from)
                            return;

                        else if (now > schedule_from)
                        {
                            var runTime = interfaceConfig.Runat;

                            if (!interfaceMetaData.ContainsKey(interfaceConfig.Interface_id))
                            {
                                interfaceMetaData.Add(interfaceConfig.Interface_id, new InterfaceMetaData(interfaceConfig));
                            }
                            else
                            {
                                _logger.LogInformation(string.Format("Interface {1} last ran at: {0}", interfaceMetaData[interfaceConfig.Interface_id].LastRanAt, interfaceConfig.Interface_id));
                            }


                            _ = Task.Run(() => runInterface(interfaceMetaData[interfaceConfig.Interface_id], runTime), CancellationToken.None);

                        }
                    }
                    _logger.LogInformation(string.Format("Tick@{0}", DateTime.Now));

                    await Task.Delay(5000, stoppingToken);
                }
            }


            void runInterface(InterfaceMetaData InterfaceData, CronExpression runTime)
            {
                _logger.LogInformation("Interface " + InterfaceData.Configuration.Interface_id + " is running !");
                Console.WriteLine("Interface " + InterfaceData.Configuration.Interface_id + " is running !");

                try
                {
                    for (int i = 0; i < configs.Count; i++)
                    {
                        if (configs.Count > 0)
                        {
                            var interface_id = InterfaceData.Configuration.Interface_id;
                            rootPath = InterfaceData.Configuration.Source;
                            destPath = InterfaceData.Configuration.Destination;
                            regx = InterfaceData.Configuration.Regx;
                            ranat = runTime;
                            //runTime = configs[i].Runat;

                            bool directoryExists = Directory.Exists(destPath);
                            if (directoryExists)
                            {
                                // eventLog1.WriteEntry($"The [{rootPath}] exists.");
                                _logger.LogInformation($"The [{rootPath}] exists.");

                                var files = Directory.GetFiles(rootPath).OrderBy(f => new FileInfo(f).CreationTime).Where(item => regx.IsMatch(item));
                                // eventLog1.WriteEntry($"Moving files from Folder: {rootPath}");
                                _logger.LogInformation($"Moving files from Folder: {rootPath}");
                                foreach (var file in files)
                                {
                                    try
                                    {
                                        startTime = DateTime.Now;

                                        File.SetAttributes(destPath, FileAttributes.Normal);
                                        File.Move(file, $"{destPath}{Path.GetFileName(file)} ");
                                        //  eventLog1.WriteEntry($"File {Path.GetFileName(file)} moved to the the {destPath} successfullly");
                                        _logger.LogInformation($"File {Path.GetFileName(file)} moved to the the {destPath} successfullly");
                                        var finishedTime = DateTime.Now;
                                    }
                                    catch (IOException)
                                    {
                                        // eventLog1.WriteEntry($"Failed moving {Path.GetFileName(file)} to the {destPath}, File is being used by another process!", EventLogEntryType.Error);
                                        _logger.LogInformation($"Failed moving {Path.GetFileName(file)} to the {destPath}, File is being used by another process! ");
                                    }
                                    finally
                                    {
                                        TimeSpan timespan = finishedTime - startTime;
                                        InterfaceData.InterfaceRanFor = DateTime.FromOADate(timespan.TotalMilliseconds);
                                    }
                                }
                            }
                            else
                            {
                                Directory.CreateDirectory(destPath);
                            }
                        }
                    }
                }
                catch (Exception)
                {
                    // eventLog1.WriteEntry("Can not access folders over the network", EventLogEntryType.Error);
                    _logger.LogInformation("Can not access folders over the network");
                }
                finally
                {
                    InterfaceData.LastRanAt = DateTime.Now;

                    _logger.LogInformation("Interface " + InterfaceData.Configuration.Interface_id + " is finished !");
                    Console.WriteLine("Interface " + InterfaceData.Configuration.Interface_id + " is finished !");
                }
              }
            }
        }

    ************************Configurations.cs*****************

    using Cronos;
    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;

    namespace OASFileProcessing
    {
        public class InterfaceConfigurations
        {
            public List<InterfaceConfiguration> Configurations { get; set; }
        }
        public class InterfaceConfiguration
        {
            public string Interface_id { get; set; }
            public string Source { get; set; }
            public string Destination { get; set; }
            public string Description { get; set; }
            public CronExpression Runat { get; set; }
            public DateTime Schedule_from { get; set; }
            public Regex Regx { get; set; }
        }
    }

    *************************InterfaceMetaData*****************************

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace OASFileProcessing
    {
        public class InterfaceMetaData
        {
            public DateTime LastRanAt { get; set; }
            public InterfaceConfiguration Configuration { get; set; }
            public DateTime InterfaceRanFor { get; internal set; }

            public InterfaceMetaData(InterfaceConfiguration config)
            {
                this.Configuration = config;
            }
        }*****************************

    Again thanks very much for your help and time, it's really appreciated.

    Seham.

    Tuesday, October 20, 2020 10:22 AM
  • Hi Seham_1981,

    Thanks for your feedback.

    I regret that I cannot reproduce your problem, since your question is related to IHostedService, you can consider posting your question on this forum for more efficient responses.

    Thank you for your understanding.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, October 21, 2020 8:01 AM