how to start a process after another async process is ended (web request independent)

Viewed 105

I am working on a video conversion web api. users will upload their videos, the api will convert it (with ffmpeg) and then store it. I am calling the conversion method from my controller. this is how the conversion method looks like:

var arguments = "-i " + inputDir + " -c:v libx264 -preset fast -crf 25 -r 23.976 -ar 44100 -ac 2 -c:a aac -strict -2 -b:a 112k " + outputDir;

var process = new Process()
{
    StartInfo = new ProcessStartInfo()
    {
        UseShellExecute = false,
        FileName = ffmpegDir,
        CreateNoWindow = true,
        Arguments = arguments
    },
    EnableRaisingEvents = true
};
process.Start();
process.Exited += (sender, args) =>
{
    //store the output file
};  

When I deployed it into production I faced some serious problems. If a single client uploads his video then there is no problem. but if multiple clients try to upload their videos at the same time then the application becomes unresponsive. I know the video conversion process takes a lot of cpu resources, that is why if multiple conversion starts then the server hangs up.

I have come up with an architecture for solution but I dont know how I can implement it. This is my idea

  1. I have to run the conversion process in a new thread so that it will be completely different from the main thread. 1 thread/process at a time no matter how many web requests are there.
  2. When a new thread tries to run a process, it will check if there are any previous thread/process already running or not. if yes then the thread will suspend and if no then the thread will start.
  3. After any thread ends, it will check if there are any pending threads or not, then repeat from step 2.

What is the best way to do it? How can I keep track if there are any threads/processes already running in the background?

1 Answers

You can create a dedicated thread that will start a new process. Then add a queue to communicate with that thread

Pseudocode:

public class ApiController
{
  private Queue<string> queue = new Queue<string>();
  private object sync = new object();

  public ApiController()
  {
    // create a thread here or on web app start
  }

  private void ThreadProc()
  {
    while (true)
    {
      string filename = null;
      lock (sync)
      {
        if (queue.Count() > 0)
          filename = queue.Dequeue();
      }

      if (filename != null)
      {
        // create process
      }
      else
      {
        Thread.Sleep(100);
        continue;
      }
    }
  }

  public void ApiMethod()
  {
    // save file from request stream and pass name of this file to thread
    string filename = ...
    lock (sync)
      queue.Enqueue(filename);
  }
}

This approach allow you to have only a single running process at any time

Related