1

I implemented progress bar to show completing status to users when video processes in background. it works well on single instance. but mixed it up when two concurrent video process started.

When two video processes initiated by two different users at same time, both users will see mixed progress status sometimes from video process 1, sometimes from another.

Video process on server side initiated with static variable.

public static MediaHandler _mhandler = new MediaHandler();

Progress indication sent to page via

[WebMethod]
public static string GetProgressStatus()
{
    return Math.Round(_mhandler.vinfo.ProcessingCompleted, 2).ToString();
}

Progress request sent by progress bar after every few seconds.

Now my question is how i can set mediahandler object which can target only one instance at a time.

e.g progress bar 01 shows status of video process 01 only

and

progress bar 02 shows status of video process 02 only

irfanmcsd
  • 6,533
  • 7
  • 38
  • 53
  • What is `MediaHandler`? I can't find any information about it in MSDN – freefaller Jul 17 '12 at 12:16
  • its third party .net ffmpeg wrapper which process videos in background and send progress completion status. – irfanmcsd Jul 17 '12 at 12:18
  • In that case, make it clear in your question... people can't be expected to know information like that!! – freefaller Jul 17 '12 at 12:19
  • problem is not related to media handler, its related to static object and their issue on concurrent requests. – irfanmcsd Jul 17 '12 at 12:20
  • That might be the situation in this case, but there are so many possible reasons for things to not work in computing, you don't want to discount any possibility. If you **don't** want to make life difficult for yourself and those trying to answer, give as much information as possible right from the start – freefaller Jul 17 '12 at 12:23
  • its general question which target my issue directly. with detail i posted here which is more confusing but helpful. http://stackoverflow.com/questions/11512235/get-proper-progress-updates-on-two-long-waited-concurrent-processes-in-asp-net – irfanmcsd Jul 17 '12 at 12:30

4 Answers4

1

Be careful with ASP.NET and static - a static whatchagot is global across sessions (users) within the same appdomain (give or take a few differences depending on the type).

Keep user information in session storage. Or, to be a bit crazy, have a static media handler object taking care of multiple sessions using session ids and query its progress using the session id. This sounds a bit smelly though but might be what you want unless you want each session to be able to spawn their own encoding.

See this answer (one of many on the subject). The Microsoft knowledgebase article however is a bit too unclear imo.

Community
  • 1
  • 1
Oskar Duveborn
  • 2,189
  • 16
  • 20
1

I suggest you generate a Guid for each new encoding request that will be used for the life of the encoding. Also I suggest that MediaHandler not be static and that your new() up one for each encoding task. GetProgressStatus() should now have a parameter for the Guid so that you can query the progress per encoding.

You will need persistence(database, static list, MSMQ...etc) to track your MediaHandler instances and or the progress of the current processing encoding if it's done serially.

rick schott
  • 21,012
  • 5
  • 52
  • 81
  • Thanks generating Guid and attaching guid value with each process solved my issue. i posted complete detail what i achieved in separate answer. – irfanmcsd Jul 18 '12 at 18:12
1

This is a very simple approach:

Have you considered the use of an static list??

Where each item in the list will be the instance of your handler running a background process. You need to identify each one of the handlers, the easiest way would be to use a Guid for each one of them.

This is a sample working code:

Output

enter image description here

As you can see, each window fires a new process and each window is updated independently

ASPX

<head runat="server">
    <title></title>
    <script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script>
    <script type="text/javascript" src="Scripts/jquery.timer.js"></script>
    <script type="text/javascript">
        var timer;
        var currentProcess;
        function getProgress() {
            $.ajax({
                url: 'LongTimeOperations.aspx/GetStatus',
                data: '{"processID": "' + currentProcess + '"}',
                contentType: 'application/json; charset=utf-8;',
                dataType: 'json',
                type: "POST",
                async: true,
                cache: false,
                success: function (msg) {
                    $("#res").append("<br/>" + msg.d);
                    var r = msg.d;
                    if (typeof (r) === 'undefined' || r === null) {
                        timer.stop();
                    }
                },
                error: function (hxr) {
                    alert(hxr.responseText);
                }
            });
        }
        $(function () {
            $("#start").click(function () {
                $.ajax({
                    url: 'LongTimeOperations.aspx/StartProcess',
                    data: '{}',
                    contentType: 'application/json; charset=utf-8;',
                    dataType: 'json',
                    type: "POST",
                    async: true,
                    cache: false,
                    success: function (msg) {
                        alert(msg.d);
                        currentProcess = msg.d;
                        timer = $.timer(getProgress, 2000, true);
                    },
                    error: function (hxr) {
                        alert(hxr.responseText);
                    }
                });
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <input type="button" id="start" value="Start Process" />
        <p>
            <div id="res"></div>
        </p>
    </div>
    </form>
</body>

Code behind

    public static List<CurrentProcess> Processes = new List<CurrentProcess>();

    [WebMethod]
    public static Guid StartProcess()
    {
        Mutex mutex = new Mutex();
        mutex.WaitOne();

        var star = Thread.CurrentThread.ManagedThreadId.ToString();
        var p = new CurrentProcess(Guid.NewGuid());
        Processes.Add(p);

        var o = Observable.Start(() =>
        {
            var cap = p;
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(2000);
                var cp = Processes.FirstOrDefault(x => x.ID == cap.ID);

                if (cp != null)
                    cp.Status = string.Format("Current Process ID: {0}, Iteration: {1}, Starting thread: {2}, Execution thread: {3}",
                        cp.ID.ToString(),
                        i.ToString(),
                        star,
                        Thread.CurrentThread.ManagedThreadId.ToString()
                        );
            }
            Processes.RemoveAll(x => x.ID == cap.ID);
        }, Scheduler.NewThread);

        mutex.ReleaseMutex();
        mutex.Close();

        return p.ID;
    }

    [WebMethod]
    public static string GetStatus(Guid processID)
    {
        var p = Processes.FirstOrDefault(x => x.ID == processID);

        if (p != null)
            return p.Status;

        return null;
    }
}

public class CurrentProcess
{
    public Guid ID { get; set; }

    public string Status { get; set; }

    public CurrentProcess (Guid id)
    {
        this.ID = id;
    }
}

Lib used

In this sample I'm using Rx to create a new thread, you can change that to use another approach

Jupaol
  • 21,107
  • 8
  • 68
  • 100
1

Thanks for sharing ideas but unfortunately no solution solve issue of concurrency in case of using static objects which is almost shared across all users. Now i made some adjustments which solved my problem.

Instead of using single static object, i used generic list object to stored all concurrent process objects in a list. Here is code.

public static List<MediaHandler> _lst = new List<MediaHandler>();

Where MediaHandler is class name responsible for processing videos.

The following function is responsible for initiating video processing

public static string EncodeVideo(string Source, string Published)
{   
 MediaHandler _mhandler = new MediaHandler(); 
 ..............
 ..............
 _mhandler.vinfo.ProcessID = Guid.NewGuid().ToString(); 
// unique guid to attach with each process to identify proper object on progress bar and get info request
// add media handler object in concurrent static list
 _lst.Add(_mhandler);
 return _mhandler.vinfo.ProcessID; // retuned unique identifier
}

Now with each progress bar request process id must be sent to function in order to send progress status of proper video processing object.

[WebMethod]
public static string GetProgressStatus(string ProcessID)
{
    string completed_process = "0";
    if (_lst.Count > 0)
    {
        int i = 0;
        for (i = 0; i <= _lst.Count - 1; i++)
        {
            if (_lst[i].vinfo.ProcessID == ProcessID)
            {
                completed_process = Math.Round(_lst[i].vinfo.ProcessingCompleted, 2).ToString();
            }
        }
    }

    return completed_process;
}

Once processing completed 100% just store all video information in object and remove media handler object from static concurrent list.

if (_lst[i].vinfo.ProcessingCompleted >= 100)
{
    // remove from list of corrent processes if processes reach this point
    // store all information of completed process and remove it from list of concurrent processes
    // e.g
    VideoInfo current_uploaded_video_info = _lst[i].vinfo;
     _lst.Remove(_lst[i]);
}

In this way unlimited number of concurrent processes and progress bar requests made possible.

irfanmcsd
  • 6,533
  • 7
  • 38
  • 53