2017-06-27 5 views
0

J'ai écrit le code suivant qui fonctionne bien mais le problème est que parfois cela me donne file being used by another process ces deux travaux accèdent et écrivent le même fichier. ClickProfileJob s'exécute en premier et répète après 5 secondes, puis le deuxième travail ClickLikeJob selon l'horaire de 5 secondes. J'ai vu quelques solutions qui avaient suggéré la même technique que j'ai codé ci-dessous.Fichier utilisé par un autre processus dans le service Windows

using Quartz; 
    using System; 
    using System.IO; 
    using Topshelf; 
    using Topshelf.Quartz; 

    namespace FinyaConsole 
    { 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      userCreds creds = new userCreds(); 

      if (creds.checkUser().Length > 3) 
      { 
       HostFactory.Run(x => 
       { 
        x.Service<GiveHeartsService>(s => 
        { 
         s.WhenStarted(service => service.OnStart()); 
         s.WhenStopped(service => service.OnStop()); 
         s.ConstructUsing(() => new GiveHeartsService()); 

         s.ScheduleQuartzJob(q => 
          q.WithJob(() => 
           JobBuilder.Create<ClickProfileJob>().Build()) 
           .AddTrigger(() => TriggerBuilder.Create() 
            .WithSimpleSchedule(b => b 
             .WithIntervalInSeconds(5) 
             .RepeatForever()) 
            .Build())); 

         s.ScheduleQuartzJob(q => 
          q.WithJob(() => 
           JobBuilder.Create<ClickLikeJob>().Build()) 
           .AddTrigger(() => TriggerBuilder.Create() 
            .WithSimpleSchedule(b => b 
             .WithIntervalInSeconds(5) 
             .RepeatForever()) 
            .Build())); 


        }); 

        //.DependsOnEventLog() 

        x.RunAsLocalSystem() 
         .StartAutomaticallyDelayed() 
         .EnableServiceRecovery(rc => rc.RestartService(1)); 

        x.SetServiceName("FinyaHearts"); 
        x.SetDisplayName("FinyaHearts"); 
        x.SetDescription("This is a service."); 
       }); 
      } 
     } 
    } 
     public class ClickProfileJob : IJob 
     { 
      public void Execute(IJobExecutionContext context) 
      { 
       try 
       { 
        using (StreamWriter sw = new StreamWriter(".\\visits_to_others.txt", true)) 
        { 

         //Write a line of text 
         sw.WriteLine($"[{DateTime.Now}] Welcome from ClickProfileJob!"); 
         Console.WriteLine($"[{DateTime.Now}] Welcome from ClickProfileJob!"); 
         //System.IO.File.WriteAllText(@"path\visit_users.txt", userLink); 
         //Close the file 
         sw.Flush(); 
         sw.Dispose(); 
         sw.Close(); 
        } 
       } 
       catch (Exception e) 
       { 
        Console.WriteLine("Exception: " + e.Message); 
       } 
       finally 
       { 
        //Console.WriteLine("Executing finally block."); 
       } 
      } 
     } 

     public class ClickLikeJob : IJob 
     { 
      public void Execute(IJobExecutionContext context) 
      { 
       try 
       { 
        using (StreamWriter sw = new StreamWriter(".\\visits_to_others.txt", true)) 
        { 

         //Write a line of text 
         sw.WriteLine($"[{DateTime.Now}] Welcome from ClickLikeJob!"); 
         Console.WriteLine($"[{DateTime.Now}] Welcome from ClickLikeJob!"); 
         //System.IO.File.WriteAllText(@"path\visit_users.txt", userLink); 
         //Close the file 
         sw.Flush(); 
         sw.Dispose(); 
         sw.Close(); 
        } 
       } 
       catch (Exception e) 
       { 
        Console.WriteLine("Exception: " + e.Message); 
       } 
       finally 
       { 
        //Console.WriteLine("Executing finally block."); 
       } 
      } 
     } 
    } 
+0

Vous avez donc 2 déclencheurs simultanés (plus ou moins) en même temps toutes les 5 secondes. Ceux-ci invoquent respectivement différentes méthodes qui tentent d'écrire dans le même fichier. Boom. Pourquoi ne pas avoir une seule minuterie qui invoque une méthode qui invoque les méthodes originales *** séquentiellement ***? De cette façon, leur exécution ne se chevauchera jamais. – spender

+0

@spender J'ai essayé de changer les secondes comme 2 secondes pour le premier travail et 7 secondes pour le deuxième travail. Il donne encore parfois l'erreur. Ces deux tâches sont différentes parce que je veux utiliser le premier pour fonctionner comme chaque semaine et le deuxième travail est chronométré pour courir après 3 jours. – Amjad

+1

Après 14 secondes? Penses-y. – spender

Répondre

0

Ce n'est pas un problème spécifique au quartz. Vous pouvez utiliser un SemaphoreSlim ou mieux un lock simple. Créez simplement un travail de base et dérivez vos autres Jobs. Puis verrouillez le LockObject dans les deux Jobs.

public abstract class LockableJobBase 
{ 
    protected static object LockObject = new object(); 
} 


public class ClickProfileJob : LockableJobBase, IJob 
{ 
    public void Execute(IJobExecutionContext context) 
    { 
     try 
     { 
      lock (LockObject) 
      { 
       using (StreamWriter sw = new StreamWriter(".\\visits_to_others.txt", true)) 
       { 
        // your sw stuff 
       } 
      } 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Exception: " + e.Message); 
     } 
     finally 
     { 
      //Console.WriteLine("Executing finally block."); 
     } 
    } 
} 

public class ClickLikeJob : LockableJobBase, IJob 
{ 
    public void Execute(IJobExecutionContext context) 
    { 
     try 
     { 
      lock (LockObject) 
      { 
       using (StreamWriter sw = new StreamWriter(".\\visits_to_others.txt", true)) 
       { 
        // your sw stuff 
       } 
      } 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Exception: " + e.Message); 
     } 
     finally 
     { 
      //Console.WriteLine("Executing finally block."); 
     } 
    } 
} 
+0

Merci, je ne savais pas comment utiliser efficacement les verrous, recommanderiez-vous un bon livre qui enseigne ce genre de sujets avancés? – Amjad

+0

Heureux que je pourrais aider;) Il ya beaucoup de livres qui sont une bonne lecture mais les bases sont faciles et vous n'avez vraiment pas besoin d'un livre pour cela. Il est plus important que vous sachiez, où et comment utiliser différents modèles et techniques. StackOverflow devrait être le premier choix quand vous avez des questions et il y a beaucoup d'autres bons sites comme CodeProject. Ps: s'il vous plaît ne pas demander sur SO pour des livres ou des tutoriels ou des trucs comme ça. Il est considéré comme offtopic et sera fermé. – Rabban