In my project, I use the ProcessCompoment and I use a timeout of 120 seconds.
$process->setTimeout(120);
$process->run();
// executes after the command finishes
if (!$process->isSuccessful()) {
$job->setResult('error');
} else {
$job->setResult($process->getOutput());
}
The problem is, when the timeout is reached Symfony return a RuntimeException, but I need to know when this command is aborted, to store an error in place of the result in my database.
Someone have an idea ?
Finally I just use a simple try-catch...
$process->setTimeout(120);
try {
$process->run();
} catch (RuntimeException $exception) {
$job->setResult('error');
}
Related
So have come across some code very similar to this. I am just wondering if someone can explain this to me.
See how it uses RX scheduler then Parallel.For and inside that a new TaskFactory.StartNew
IDisposable subscription = someObservable.ObserveOn(ThreadPoolScheduler.Instance)
.Subscribe(o =>
{
Parallel.ForEach(xxxs,
x =>
{
var theKey = x.Key;
if (!theTasks.ContainsKey(theKey) ||
theTasks.ContainsKey(theKey) && theTasks[theKey].IsCompleted)
{
theTasks[theKey] = Task.Factory.StartNew(
() =>
{
.....
}
catch (CommunicationObjectAbortedException ex)
{
....
}
catch (ObjectDisposedException ex)
{
....
}
catch (Exception e)
{
....
}
});
}
});
},
ex =>
{
....
},
() =>
{
....
});
}
I know what all these things do individually, but am not really sure what the combined threading effect here is. Can anyone hazzard a guess
Ah yes, the concurrency Turducken.
ThreadPoolScheduler schedules work on the thread pool which is distinct from the task pool. ThreadPoolScheduler was meant to be used to on platforms where a task pool was not available - prefer TaskPoolScheduler when possible.
It feels like the writer was trying to save up the task pool for only the task at hand (pardon the pun), by using the thread pool.
Parallel.ForEach blocks until the loop has been completed. So while it was running on the thread pool, when a new item is emitted, do the next ForEach on a borrowed thread from the thread pool.
As for the inner bit, the writer wants one Task to be run per unique key, if isn't already running.
I've spend several hours trying to resolve this issue. Google and Stackoverflow didn't help much either. So any advice is most welcome here.
I'm trying to apply a rollback logic with transactions when updating two tables in relation:
The code in general is:
// ...
$em = $this->getDoctrine()->getEntityManager();
$em->getConnection()->beginTransaction();
foreach($dataArr as $data) {
$userObj = $em->getRepository('AcmeBundle:User')->find($userId);
$userObj->setActive(1);
$em->persist($userObj);
$em->getConnection()->commit();
}
$storeObj = $em->getRepository('AcmeBundle:Store')->find($storeId);
$storeObj->setIsOpen(1);
$em->persist($storeObj);
$em->getConnection()->commit();
try {
$em->flush();
$em->clear();
} catch(Exception $e) {
$em->getConnection()->rollback();
$em->close();
throw $e;
}
My PDO drivers are enabled, updating without transactions works as expected, but once I beginTransaction() and try to commit() nothing works and I get the There is no active transaction. exception.
Some sources suggested using only commit() without persist() but it doesn't make any difference. I'm probably doing something really stupid here, but I just cannot see what it is.
After
$this->em->getConnection()->beginTransaction();
you must write:
$this->em->getConnection()->setAutoCommit(false);
It works for me :)
I once accidentally got this error
by doing following:
$em->getConnection()->beginTransaction();
try {
$em->persist($entityA);
$em->flush();
$em->persist($entityB);
$em->flush();
$em->getConnection()->commit();
//exception thrown here
$mailer->send($from, $to, $subject, $text);
} catch (\Exception($ex)) {
$em->getConnection()->rollback();
}
So, you already have guessed that there should not be any code after commit as in the case when this arbitary code($mailer service in our example) throws an exception transaction would be closed before the moment catch block is executed. Maybe this will save a minute or two to somebody:)
Since the version 1.5.2 of DoctrineBundle, you can configure the connection to use auto_commit in the configuration of your project.
# app/config/config.yml (sf2-3) or config/doctrine.yaml (sf4)
doctrine:
dbal:
auto_commit: false
As #prodigitalson correctly suggested I needed to do a commit() before the flush() in order for the get the queries executed. So the working code now is:
$em = $this->getDoctrine()->getEntityManager();
$em->getConnection()->beginTransaction();
foreach($dataArr as $data) {
$userObj = $em->getRepository('AcmeBundle:User')->find($userId);
$userObj->setActive(1);
$em->persist($userObj);
// this is no longer needed
// $em->getConnection()->commit();
}
$storeObj = $em->getRepository('AcmeBundle:Store')->find($storeId);
$storeObj->setIsOpen(1);
$em->persist($storeObj);
// this is no longer needed
// $em->getConnection()->commit();
try {
// Do a commit before the FLUSH
$em->getConnection()->commit();
$em->flush();
$em->clear();
} catch(Exception $e) {
$em->getConnection()->rollback();
$em->close();
throw $e;
}
Is there a way to specify the wait time of retrying a message for a particular exception?
E.g. If object is in SomethingInProgress status, throws an SomethignInProgressException and I want to the message to be retry after 40m. Or is it more appropriate to raise a SomethingInProgressEvent and use bus.defer?
This is part of the reason why Rebus does not have the concept of second-level retries - I've simply not seen any way that this function could be created in a way that was generic and still flexible enough.
To answer your question shortly: No, there's no (built-in) way of varying the time between retries for a particular exception. In fact, there's no way to configure a wait time between retries at all - failing messages will be retried as fast as possibly, and then moved to the error queue if they keep failing to avoid "clogging up the pipes".
In your case, I suggest you do something like this:
public void Handle(MyMessage message) {
var headers = MessageContext.GetCurrent().Headers;
var deliveryAttempt = headers.ContainsKey("attempt_no")
? Convert.ToInt(headers["attempt_no"])
: 0;
try {
DoWhateverWithThe(message);
} catch(OneKindOfException e) {
if (deliveryAttempt > 5) {
bus.Advanced.Routing.ForwardCurrentMessage("error");
return;
}
bus.AttachHeader(message, "attempt_no", deliveryAttempt + 1);
bus.Defer(TimeSpan.FromSeconds(20), message);
} catch(AnotherKindOfException e) {
if (deliveryAttempt > 5) {
bus.Advanced.Routing.ForwardCurrentMessage("error");
return;
}
bus.AttachHeader(message, "attempt_no", deliveryAttempt + 1);
bus.Defer(TimeSpan.FromMinutes(2), message);
}
}
which I just wrote off the top of my head without being 100% certain that it actually compiles ... but the gist of it is that we track how many delivery attempts we've made in a custom header on the message, bus.Deferring the message an appropriate time span for each failed delivery attempt, immediately forwarding the message to the error queue when our max # of delivery attempts has been exceeded.
I hope that makes sense :)
A more recent example of how to do this is:
public async Task Handle(IFailed<MyMessage> message)
{
var maxAttempts = 10;
var optionalHeaders = new Dictionary<string, string>();
if (message.Headers != null && message.Headers.ContainsKey("attemptNumber"))
{
// increment the attempt number
var attemptNumber = int.Parse(message.Headers["attemptNumber"]);
attemptNumber++;
optionalHeaders.Add("attemptNumber", attemptNumber.ToString());
if (attemptNumber > maxAttempts)
{
// log I give up message, message will move to dead queue
return;
}
}
else
optionalHeaders.Add("attemptNumber", "1");
// if message failed to process, defer processing for 5 minutes and try again
await Bus.Defer(TimeSpan.FromMinutes(5), message.Message, optionalHeaders);
}
I have a C# SignalR client and I want to do some actions upon success/failure of the connection to my server. Here is my code :
this.connection.Start().ContinueWith(task =>
{
if (task.IsFaulted)
{
this.OnRaiseServerConnectionClosedEvent();
}
else
{
this.JoinGroup();
this.StopTimer();
this.OnRaiseServerConnectionOpenedEvent();
}
});
}
The else block is always executed, not caring if a server is here or not...
I have also tried with await or with Wait() but same scenario.
I understand .net tasks correctly I think but here I am stuck.
Right now my code looks like
try
{
this.connection.Start().Wait();
if (this.connection.State == ConnectionState.Connected)
{
this.JoinGroup();
this.StopTimer();
this.OnRaiseServerConnectionOpenedEvent();
}
}
catch (AggregateException)
{
this.OnRaiseServerConnectionClosedEvent();
}
catch (InvalidOperationException)
{
this.OnRaiseServerConnectionClosedEvent();
}
When no server is present, the task created by the Start() method returns without fault and with status connecting. You have to check the state of the connection if you want to follow with some actions or retry connecting.
The task you are receiving from Connection.Start is likely cancelled due to a timeout instead of being faulted. This should be an easy fix:
this.connection.Start().ContinueWith(task =>
{
if (task.IsFaulted || task.IsCanceled)
{
this.OnRaiseServerConnectionClosedEvent();
}
else
{
this.JoinGroup();
this.StopTimer();
this.OnRaiseServerConnectionOpenedEvent();
}
});
If you use Wait() instead of ContinueWith, an AggregateException containing an OperationCanceledException in its InnerExceptions collection will be thrown when the task is canceled.
I am a new to WCF. I have written ajax to use a web service before, but on this project I am trying to use ajax to WCF.
After I build the project and wcf using ajax, I receive the return successfully. But, 10 or more minutes later I don't get a return, the ajax calls the error function, and the fiddler returns nothing.
If I rebuild the project without any source modifying, I receive the return successfully again.
Is their anybody who has experienced this or knows why this might be?
Thank You.
Most likely you're not closing the connections. You should wrap all your calls in Try/Catch/Finally blocks.
In C#:
ServiceClient service = GetService();
try
{
SomeRequest request = new SomeRequest();
SomeResponse response = service.GetSome(request);
return response.Result;
}
catch (Exception ex)
{
// do some error handling
}
finally
{
try
{
if (service.State != CommunicationState.Faulted)
{
service.Close();
}
}
catch (Exception ex)
{
service.Abort();
}
}
or VB
Dim service As ServiceClient = GetService()
Try
Dim request As New SomeRequest()
Dim response As SomeResponse = service.GetSome(request)
Return response.Result
Catch ex As Exception
' do some error handling
Finally
Try
If service.State <> CommunicationState.Faulted Then
service.Close()
End If
Catch ex As Exception
service.Abort()
End Try
End Try
Here is the best practice for calling WCF services:
public static void CallService<T>(Action<T> action) where T
: class, ICommunicationObject, new()
{
var client = new T();
try
{
action(client);
client.Close();
}
finally
{
if (client.State == CommunicationState.Opened)
{
try
{
client.Close();
}
catch (CommunicationObjectFaultedException)
{
client.Abort();
}
catch (TimeoutException)
{
client.Abort();
}
}
if (client.State != CommunicationState.Closed)
{
client.Abort();
}
}
}
Each WCF call should create a new instance of your service class. This code allows you to enforce that and just call the services like this:
CallService<MyService>( t => t.CallMyService());