Open vinok88 opened 5 years ago
Let me explain why the spec says this.
However, I agree that it is problematic for the case where the sending worker wants to terminate without waiting for the receiving worker to terminate.
I believe this is also related to a similar concern raised regarding the following in the spec.
"If the receive-action corresponding to an async-send-action has a non-empty failure type, then it is a compile-time error unless it can be determined that a sync-send-action or a flush-action will be executed before the sending worker terminates with success."
Yes, that’s related.
May I ask what is the conclusion of this discussion?
If I give some code samples, in the below example even though there is a panic at the receiver, the sender terminates successfully, without abruptly panicking, due to the fire and forget nature in the current implementation.
import ballerina/io;
import ballerina/lang.runtime;
int x = 5;
public function main() {
worker w1 returns string {
5 -> w2;
io:println("w1 almost done");
return "w1 done";
}
worker w2 {
runtime:sleep(2);
x-=1;
if(x>1) {
panic error("error at w2");
}
io:println("w2 receiving");
int x = <- w1;
io:println("w2 received " + x.toBalString());
}
string p = wait w1;
io:println("wait: ", p);
}
gives
Running executable
w1 almost done
wait: done
So it seems, it is better to do as the spec says so that the panics in the receiver are reflected in the sender. Now if the user want to trap the panic, it cannot be done same way as sync send which is shown below.
import ballerina/io;
import ballerina/lang.runtime;
int x = 5;
public function main() {
worker w1 returns string {
error? unionResult = trap 5 ->> w2;
io:println("w1 almost done");
return "w1 done";
}
worker w2 {
runtime:sleep(2);
x-=1;
if(x>1) {
panic error("error at w2");
}
io:println("w2 receiving");
int x = <- w1;
io:println("w2 received " + x.toBalString());
}
string p = wait w1;
io:println("wait: ", p);
}
gives
Running executable
w1 almost done
wait: w1 done
Seems the panic can be trapped only if we wait for the sender like the below, because we can't use trap
with async send
or just at the end of the worker. It is not seen currently because we fire and forget.
import ballerina/io;
import ballerina/lang.runtime;
int x = 5;
public function main() {
worker w1 returns string {
5 -> w2;
io:println("w1 almost done");
return "w1 done";
}
worker w2 {
runtime:sleep(2);
x-=1;
if(x>1) {
panic error("error at w2");
}
io:println("w2 receiving");
int x = <- w1;
io:println("w2 received " + x.toBalString());
}
string|error p = trap wait w1;
io:println("wait: ", p);
}
gives
Running executable
w1 almost done
wait: w1 done
So should we change the implementation to what is said in the spec or is it okay for the sending worker to terminate without waiting for the receiving worker to terminate or to get the messages?
My conclusion is:
Please feel free to suggest mechanisms to accomplish 2.
Here's an idea to solve this (without new syntax):
never
Description: The spec says "If a worker W is about to terminate normally and there are messages still to be sent in a queue (which must be the result of executing an async-send-action), then the worker waits until the messages have been received or some receiving worker terminates."
This behavior restricts the implementation of fire and forget like scenarios since the sender always getting blocked until the sent async messages were sent. IMO, the worker should terminate, disregarding the async worker messages are sent or not.
In fact, the flush action is there for this same behavior. Spec says, "If peer-worker is specified, then flush waits until the queue of messages to be received by peer-worker is empty or until the peer-worker terminates."
I think this worker termination behavior restricts having a pure worker async send. Shall we remove this part, since the same can be achieved through flush action?
version: 2019R3
Suggested Labels:
Code sample that shows issue:
Related Issues: