0

I have a controller and a PythonJobRepository where I call a python scrypt. This is the repository

    public class PythonJobRepository
{
    private Process process { get; set; }
    private readonly DatabaseContext _context;
    public bool IsJobRunning
    {
        get
        {
            return process.HasExited;
        }
    }
    public PythonJobRepository(DatabaseContext context)
    {
        _context = context;
    }

    public async Task<string> StartJobAsync()
    {
        List<SearchTerms> searchTerms = await _context.SearchTerms.ToListAsync();
        var json = JsonConvert.SerializeObject(searchTerms);
        json = json.Replace("\"", "'");
        ProcessStartInfo processInfo = new ProcessStartInfo();
        string scriptPath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Python\\scrapeGoogle.py");
        processInfo.FileName = "python";
        processInfo.Arguments = string.Format("{0} \"{1}\"", scriptPath, json);
        processInfo.UseShellExecute = false;
        processInfo.CreateNoWindow = true;
        processInfo.RedirectStandardOutput = true;
        processInfo.RedirectStandardError = true;
        process = Process.Start(processInfo);
        using (StreamReader reader = process.StandardOutput)
        {
            string stderr = await process.StandardError.ReadToEndAsync();
            var result = await reader.ReadToEndAsync();
            process.WaitForExit();
            process.Close();
            if (stderr == "")
            {
                return result;
            }
            else
            {
                return stderr;
            }
        };
    }

    public void StopJob()
    {
        if (!process.HasExited)
        {
            process.Kill();
        }

    }
}

And I register it as a Transient

services.AddTransient<PythonJobRepository,PythonJobRepository>();

I inject this repository in my controller and I run the StartJobAsync() method. The problem is when I call StopJob(), the process instance is null. I am pretty new to c# and asp, hope someone can help me

Filip Laurentiu
  • 558
  • 2
  • 5
  • 20
  • 1
    is `process` set anywhere? do remember that your `process` being set inside `StartJobAsync` only there for that one http request. So, a subsequent http request, it will be null. – Bagus Tesa Oct 01 '19 at 07:21
  • is set here process = Process.Start(processInfo); . And with another http request I want to stop the process. If this is wrong, can you suggest an alternative? – Filip Laurentiu Oct 01 '19 at 07:23
  • probably store the resulting process id somewhere persistent. then use that [process id to grab process instance](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.getprocessbyid?view=netframework-4.8) for the other http request. that being said, i noticed you stop the process on a single http request - that `process.Close();` - and i do wonder, why did you need a "stop" command on it. are you expecting the process can be interrupted mid way? – Bagus Tesa Oct 01 '19 at 07:30
  • It's a long running script and I need to implement a stop method to be on the safe side – Filip Laurentiu Oct 01 '19 at 07:33

2 Answers2

0

You're adding your service as Transient, which means a new instance will be created every time it's injected via DI, even if it's in the same request.

If you want to start your process in one request and stop it in another, you need to add it as a singleton, because that's the only way your service will persist between requests:

services.AddSingleton<PythonJobRepository,PythonJobRepository>();

For reference, here are the three service lifetimes:

  • Transient: services are created each time they're requested from the service container
  • Scoped: services are created once per client request
  • Singleton: services are created the first time they're requested; every subsequent request uses the same instance.
Métoule
  • 8,373
  • 36
  • 62
  • This raise an error "Some services are not able to be constructed". I can't inject a scoped service in a singleton scoped class – Filip Laurentiu Oct 01 '19 at 07:31
  • 1
    You inject your DbContext, and that's not a singleton. I suggest you read your search terms outside your Python service, which you then pass to your `StartJobAsync` method. That way, your singleton no longer depends on your DbContext. – Métoule Oct 01 '19 at 07:36
0

The solution was to remove the injection of DatabaseContext from the repository so I can make the repository a singleton. And now, I pass data from the controller to the repository

Filip Laurentiu
  • 558
  • 2
  • 5
  • 20