Requirement :
Candidates will Fill Application Form.
HR will review the application and submits for Technical Team Approval(P2).
After Technical team review HR need not to wait for Manger approval and HR should be able to get technical team data(with or without manager approval).
HR should be able to submit for Final Approval.
P1:
P2:
Solutions I have tried:
If i use Collapsed sub process i need to wait till the completion of Manager Approval task.
I tried using the sub process, throwing and catching events. Created two sub process, 1st sub process will throw signal and second sub process will catch signal if HR submits another application the 2nd sub process will not catch the signal.
If i use Call Activity multi-instance type as Sequential i need to provide Cardinality it will be fixed number of application HR will be able to submit for Technical Approval, in my case it should not be fixed number of loop.
If i use Call Activity, the Call Activity will not share its data to P1 process, in my case data should be shared from P2 to P1.
Kindly any one help me.
Thanks & Regards
Amruta Wandakar
Related
In short, remaining in the HTTP context, I would like the user, after clicking on an order completion button, not to wait for the mails to be sent before being sent back to a "thak you page".
I saw that HostingEnvironment.QueueBackgroundWorkItem could help me with this but there is always the risk of it being killed by IIS recycling.
What is the best solution to do this?
I know the best would be to develop a separate console solution but it wouldn't be worth it for 3/4 emails, alternatively I could consider speeding it up by making them asynchronous?
Protected Sub btnConcludiOrdine_Click(sender As Object, e As System.EventArgs) Handles btnConcludiOrdine.Click
If IsValidOrder(Me._cart, msg) Then
If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
'Update quantity in db
Dim mail As New EmailBLL
mail.SendOrderNotice(Me._cart, Me._lang) '2 Mails
mail.SendProductNotice() '2 Mails
End If
Else
Response.Redirect("*Error URL*")
End If
End Sub
The way you approach this is as suggested – start a task, or so called new processor thread.
So, what you would do is break out the code – this even works if code behind is for a web form.
So, the first step is to move out the “slow” parts, or the parts we want to run separate.
The main issue is that to start/launch/want/desire/achieve a brand new processor thread?
The sub call CAN ONLY PASS ONE “parameter” and the sub can only accept one parameter!!!!!
I note in your case that routine needs two values.
However, that “one parameter” can be a array of “many” values, or even a collection or whatever. In our case we pass the two values.
So just keep in mind that what you call can NOT update or “use” the values of controls on the form – the instance of that form will go out of scope.
But we can of course PASS the values you need. This will allow that routine to run 100% independent of the web form.
I also VERY strong suggest that if you DO place the sub in the same web page code behind? You should/can mark that sub as shared. Doing so will allow the compiler to get mad at you and spit out errors if that routine say tries to use or update a control value on the form.
However, it is MUCH better is to place this sub in a separate standard code module out side of the web forms code behind.
Regardless of above, we can now re-write the code we have as this:
If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
Dim myInfo(1) as object
myInfo(0) = me.cart
myInfo(1) = me_._lng
Call MyUpdateQ(myInfo)
End If
' bla bla lba
Shared Sub MyUPdateQ(p() as object)
'Update quantity in db
Dim mail As New EmailBLL
mail.SendOrderNotice(p(0),p(1)
mail.SendProductNotice() '2 Mails
End Sub
Ok, so far, we not achieved much, but we re-writing to accept the ONE array is KEY here.
So, now now make sure the above runs/works and is all happy.
Now, because we moved out the "work load" to that one routine, it is now a simple matter to start a thread.
Now, Our above code becomes this:
Protected Sub btnConcludiOrdine_Click(sender As Object, e As System.EventArgs) Handles btnConcludiOrdine.Click
If IsValidOrder(Me._cart, msg) Then
If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
Dim myInfo(1) as object
myInfo(0) = me.cart
myInfo(1) = me_._lng
Dim MyThread As New Thread(New ParameterizedThreadStart(AddressOf MyUpdateQ))
MyThread.Start(myInfo)
End If
Else
Response.Redirect("*Error URL*")
End If
End Sub
Shared Sub MyUPdateQ(p() as object)
'Update quantity in db
Dim mail As New EmailBLL
mail.SendOrderNotice(p(0),p(1)
mail.SendProductNotice() '2 Mails
End Sub
That is it. Now when you click your button it will wait ZERO time, since the long running routine is now going to run 100% as a separate thread. And this will also mean that when the user clicks the button - the page will respond instant and post back to user will be done. So if that thread takes 6 seconds, or even 25 seconds, the user will not notice this delay.
Just push your sending mail logic in Task and if you are not interested in result don't await it. c# syntax
Task.Run(() => SendEmail());
I have a very long running process in an ASP.net application that we desperately need to dramatically shorten. The process in question is charging a large number of credit cards. Currently it performs at about 1 charge per second. We need this to be more like 10 per second.
So we decided that utilizing multiple simultaneous threads would be one way to go. So we basically take this large list of orders to process, divide the list into ten lists and then spawn a new thread to process each of the ten lists simultaneously.
An additional complication of this process is that we need to report progress on this process, and not only to the user session that initiated the process, but to any user, in any session in the application. So for example, if I log in and start this process, I will see a progress bar. If after I initiate the process, and it is still running, another user logs in elsewhere and goes to this same page, they will also see the progress bar.
I did some research and thought that I could use Application variables to store the relevant bits of information required to report progress. The client polls the server on a regular basis whenever on this page to see if there are any threads running, and if so, it returns various statistics on the progress of the process back to the client.
It would seem that this approach does not work. A simple counter of the number of currently running threads does not work as expected. It seems that the so-called thread safety of the Application object is safe in that no two threads will be able to access the same variable simultaneously, but not safe in that if two threads both attempt to increment a variable, one of them will be able to increment it, and the other will not, and rather than queue up and increment it in turn, the second thread just moves on. I'm sure this is my thread safety ignorance shining through.
Another issue is that using Debug.Print or Debug.WriteLine seem to be the same kind of "thread-safe" as the Application object. As each thread starts, we use Debug.WriteLine to output the name and start time of the thread, and as it completes, we do the same thing to write that it completed. We consistently see ten threads start and four threads end in the debug window.
I don't think we need to use Application.Lock() and Application.Unlock(), but I have tried it both with and without those calls before and after every write operation, but to no avail- the results are the same either way.
I have a ton of code, so I'm not sure exactly which parts to share, but here are some of the relevant parts:
This is how we create and start the threads:
For Each oBatch As List(Of Guid) In oOrderBatches
Dim t As New Threading.Thread(Sub() ProcessPaymentBatch(oBatch, clubrunid, oToken.UserID))
t.IsBackground = True
t.Start()
Next
Here is the sub that is started by each thread:
Private Sub ProcessPaymentBatch(oBatch As List(Of Guid), clubrunid As String, UserID As Guid)
ThreadsRunning(clubrunid) += 1
Try
Debug.Print("Thread Start")
For Each oID As Guid In oBatch
‘Do a bunch of processing stuff…
Next
Finally
ThreadsRunning(clubrunid) -= 1
Debug.Print("Thread End")
End Try
End Sub
Finally, this is an example of one of the application variables that the threads attempt to access, but seems to be failing.
Private Const _THREADSRUNNING As String = "ThreadsRunningThisRun_"
Public Property ThreadsRunning(clubid As String) As Integer
Get
Dim sToken As String = _THREADSRUNNING & clubid
If Application(sToken) Is Nothing Then
ThreadsRunning(clubid) = 0
End If
Return Application(sToken)
End Get
Set(ByVal value As Integer)
Debug.Print(value)
Dim sToken As String = _THREADSRUNNING & clubid
Application.Lock()
Application(sToken) = value
Application.UnLock()
End Set
End Property
The Debug output from this property looks something like this:
Thread Start
1
Thread Start
Thread Start
1
1
4
Thread End
5
3
Thread Start
6
3
1
-1
Thread End
-2
-3
I can't understand why there would be a different number of "Thread Start" and "Thread End" debug statements, and I don't understand how the thread count could get to negative numbers. This is why I am confused by the thread safety of the Application and Debug objects.
Your help in this matter would be greatly appreciated!
Nevermind, I was just being an idiot. The problem had nothing to do with the Application or Debug objects not being thread safe, the problem was in my methodology (as was expected really).
To clarify, the issue was that we were locking the global variables in the application object when writing, but not when reading. We then tried also locking when reading, but still had the same problem. What we failed to realize was that when incrementing a value, you are getting the current value, adding onto that, then setting the new value. The lock needed to bridge all three of those operations, so it goes like this:
Lock
Get
Add
Set
Unlock
What we were doing previously was:
Lock
Get
Unlock
Add
Lock
Set
Unlock
Which allowed for multiple threads to Get and then Set the same values as one another, which explains all of the oddities we were seeing in the debug window.
I have subscribed WorkflowFinishActivityEvent with TransactionCommitted phase. I am getting the details of the current finished activity like below
Performer of the current finished activity
foreach(var performer in currentactivity.Performers)
{
string Performeroftheactivity= performer .title.tostring();
}
Finish Message of the current finished activity
string finishmessage = currentactivity.FinishMessage.Tostring()
My Question:
I would like to take the Next assigned activity title and assignee from the current finished activity event.
Could anyone help me how to get these? I don’t see any relevant Properties or methods in the API.
You can get the next activity by loading the current process definition, determining the position of the current activity, and figuring out what's next.
This is more or less shown in this post by Mihai Cadariu.
EDIT - Removed silly comment about this not being supported. Since you're in an event system, that code will work. If you want to use it in a Workflow automatic activity then you would have to use the CoreService.
You have next assignee on FinishActivityEventArgs.ActivityFinish.NextAssignee. As for next activity - there's no way to know it for the moment. Consider subscribing to activity instance save event args. This way you will catch what activity was created and who is the assignee.
I have a web service with three methods: StartReport(...), IsReportFinished(...) and GetReport(...), each with various parameters. I also have a client application (Silverlight) which will first call StartReport to trigger the generation of the report, then it will poll the server with IsReportFinished to see if it's done and once done, it calls GetReport to get the report. Very simple...
StartReport is simple. It first generates an unique ID, then it will use System.Threading.Tasks.Task.Factory.StartNew() to create a new task that will generate the report and finally return the unique ID while the task continues to run in the background. IsReportFinished will just check the system for the unique ID to see if the report is done. Once done, the unique ID can be used to retrieve the report.
But I need a way to cancel the task, which is implemented by adding a new parameter to IsReportFinished. When called with cancel==true it will again check if the report is done. If the report is finished, there's nothing to cancel. Otherwise, it needs to cancel the task.
How do I cancel this task?
You could use a cancellation token to cancel TPL tasks. And here's another example.
here is the problem :
there is classic asp app which is calling lame.exe for encoding mp3s for lots of time per day
and there is no control of the way of calling lame.exe from several users in another word there is no queue for that purpose.
so here is what I am thinking about :
//below code all are pseudo-code
//process_flag and mp3 and processId all are reside in a database
function addQ(string mp3)
add a record to database
and set process_flag to undone
then goto checkQ
end function
function checkQ()
if there is a process in queue list and process_flag is undone
sort in by processID asc
for each processID
processQ(processID)
end for
end function
function ProcessQ(int processID)
run lame.exe with the help of wscript.exe
after doing the job set the process_flag to done
end function
so I just want to know is there any better solution?
or any other approaches out there?
regards.
Looks like a reasonable approach for classic asp.
Just make sure that in your checkQ function, you are only retrieving queue items that have the process_flag set to undone, or you might be trying to re-process the same items over and over.
Read this article for another approach using MSMQ - it starts by creating a new Public Queue, then sending messages to it from your asp page. It also required an additional executable to process queued items.
This is a perfect application for MSMQ. Let proven code handle the reliable messaging, concurrency control etc. so you can just focus on the application logic.