Using ServiceBusTrigger in the Webjobs SDK 3.x, can the Singleton attribute use a UserProperty as the scope? - azure-webjobs

I am using a ServiceBusTrigger to execute code when receiving a message. I would like to use the Singleton attribute to limit which messages can be executed in parallel. This attribute allows specifying a scope bound to properties on the incoming message, such that messages with different values can be executed in parallel but ones with the same value must be done serially.
This works when using top level properties on the incoming message object like CorrelationId.
Example
[Singleton("{CorrelationId}", SingletonScope.Function, Mode = SingletonMode.Function)]
public async Task HandleMessage(
[ServiceBusTrigger("my-topic-name", "my-subscription-name"), ServiceBusAccount("my-account-name")]
Message message,
CancellationToken cancellationToken
)
{
await Task.Yield();
}
What I am struggling to figure out is how to achieve the same behavior with user properties on the message. These are stored in the UserProperties dictionary on the Message object. I'm not seeing a way to refer to these with the binding statement in the Singleton attribute, but it seems like this would be a very common use case when combining Singleton with ServiceBusTrigger

The Service Bus Bindings exposes Message Metadata in binding expressions. So, userProperties.<key> should do the trick.

Related

Akka get response as ComletedStage from actor

I am referring to api
Patters.ask(actor, msg, duration);
here is sample
class MyActor extends AbstractBehavior{
interface Command{}
interface SomeMessage implements Command{ INSTANCE}
public Reveive<Comamnd> receive(){
return newReceiveBuilder().onMessage(SomeMessage.class, this::someMessage).build();
}
private Behavior<Command> someMessage(SomeMessage ref){
System.out.println("Dru lalal");
}
}
ActorRef<MyActor.Command> myActor = ...;
Future<Object> future = Patterns.ask(myActor, SomeMessage.INSTANCE, Duration.ofMillis(10000));
What is gone be object ?
Obviously this won't compile. Some part of picture is missing, but javadoc doesn't state what.
Call "Patterns.ask" suppose to return future with object, those value is provided by actor as business logic. But there is not business logic in actor. I assume there is suppose to be some kind of convention or mapping for method that returns value with what "Patters.ask" triggers.
Same is true about back logic. I will not able to define receiver since it expect to return Receiver not SomeObject and thus, api want't let me bind result to some message. Only thing I can do is manually pass ComputableFuture
ComputableFuture<MyOBject> future = new ComputableFuture<>();
myActor.tell(new Message(future));
private Behavior<Command> someMessage(Message message){
var result = compute();
message.future.comlete(result);
}
And here we go, I have manually manage everything, also issues with passing non serializable message, lifecycle of objects and so on.
Wrong objects is used. Instead of "AskPattern.ask" for new java typed dsl, I used classic "Patterns.ask".
Most of times new api objects has same object name but located in different package. I used to check only package name becouse while playing with in IDE they always next to each other since name is the same. I got used to ignore the classic "com.akka" objects while playing with api.
And here I got into trap, object name is different and not placed in IDE next to "classic" package object.

In Akka Typed Cluster Sharding, is it safe to persist an EntityRef for future use?

I'm currently looking at making two different persistent actors communicate with each other. In particular:
Given an Actor A exists
When an Actor B is spawned
Then Actor B must have a reference to Actor A
And Actor B must be able to continuously send messages to Actor A even after relocation
I know that there are two options:
// With an EntityRef
val counterOne: EntityRef[Counter.Command] = sharding.entityRefFor(TypeKey, "counter-1")
counterOne ! Counter.Increment
// Entity id is specified via an `ShardingEnvelope`
shardRegion ! ShardingEnvelope("counter-1", Counter.Increment)
The second option seems like a nice way to go since I'll be delegating the resolution of the actual reference to the entity to Akka. I'll probably just need to pass some wrapper function to my Actor on instantiation. For example
val shardRegionA: ActorRef[ShardingEnvelope[Counter.Command]] =
sharding.init(Entity(TypeA)(createBehavior = entityContext => A()))
def delegate_A(id,message) = {
shardRegionA ! ShardingEnvelope(id,message)
}
val shardRegionB: ActorRef[ShardingEnvelope[Counter.Command]] =
sharding.init(Entity(TypeB)(createBehavior = entityContext => B(delegate_A)))
--------
object B {
def apply(delegate) = {
...somewhere inside the state...
delegate("some_id_of_A", Message("Hello"))
...somewhere inside the state...
}
}
But, I'd also like to understand whether the first option is simpler because the EntityRef might be safely persistable in the state/events.
object B {
def apply(entityRefA : EntityRef[A]) = {
EventSourcedBehavior[...](
emptyState = State(entityRefA)
)
}
}
Anyone have any insights on this?
EntityRef isn't safely persistable in state/events (barring some very fragile reflection-based serialization), since it doesn't expose the information which would allow a deserializer to rebuild an equivalent EntityRef. The default Jackson serialization also does not usefully deserialize EntityRefs.
There's a PR up as of the time of this answer to allow the "definitional" components of an EntityRef to be extracted for serialization (e.g. so EntityRef[Employee.Command] could be JSON serialized as { "entityId": "123456789", "typeKey": "EMPLOYEE" }. That PR would still require custom serialization for any messages, persisted events, or state (if snapshotting) which contain EntityRefs, but at least it would then be possible to include EntityRefs in such objects.
Until that time, you shouldn't put EntityRefs into messages, events, or snapshottable state: instead you basically have to put the IDs into those objects and send messages wrapped in ShardingEnvelopes to the shard region actor (which is what EntityRef.tell does anyway). In some cases, it might be reasonable to maintain a mapping of entity IDs to EntityRefs in a non-persistent child actor and send messages to EntityRefs via that child actor, or if willing to block or really contort your protocol, do asks to that child to resolve EntityRefs for you.
EDIT to note that as of Akka 2.6.13, it's possible to implement a custom serializer to handle EntityRefs; the Jackson serializers at this point do not support EntityRef. A means of resolving a type key and entity ID into an EntityRef would have to be injected into the serializer.

MismatchingMessageCorrelationException : Cannot correlate message ‘onEventReceiver’: No process definition or execution matches the parameters

We are facing an MismatchingMessageCorrelationException for the receive task in some cases (less than 5%)
The call back to notify receive task is done by :
protected void respondToCallWorker(
#NonNull final String correlationId,
final CallWorkerResultKeys result,
#Nullable final Map<String, Object> variables
) {
try {
runtimeService.createMessageCorrelation("callWorkerConsumer")
.processInstanceId(correlationId)
.setVariables(variables)
.setVariable("callStatus", result.toString())
.correlateWithResult();
} catch(Exception e) {
e.printStackTrace();
}
}
When i check the logs : i found that the query executed is this one :
select distinct RES.* from ACT_RU_EXECUTION RES
inner join ACT_RE_PROCDEF P on RES.PROC_DEF_ID_ = P.ID_
WHERE RES.PROC_INST_ID_ = 'b2362197-3bea-11eb-a150-9e4bf0efd6d0' and RES.SUSPENSION_STATE_ = '1'
and exists (select ID_ from ACT_RU_EVENT_SUBSCR EVT
where EVT.EXECUTION_ID_ = RES.ID_ and EVT.EVENT_TYPE_ = 'message'
and EVT.EVENT_NAME_ = 'callWorkerConsumer' )
Some times, When i look for the instance of the process in the database i found it waiting in the receive task
SELECT DISTINCT * FROM ACT_RU_EXECUTION RES
WHERE id_ = 'b2362197-3bea-11eb-a150-9e4bf0efd6d0'
However, when i check the subscription event, it's not yet created in the database
select ID_ from ACT_RU_EVENT_SUBSCR EVT
where EVT.EXECUTION_ID_ = 'b2362197-3bea-11eb-a150-9e4bf0efd6d0'
and EVT.EVENT_TYPE_ = 'message'
and EVT.EVENT_NAME_ = 'callWorkerConsumer'
I think that the solution is to save the "receive task" before getting the response for respondToCallWorker, but sadly i can't figure it out.
I tried "asynch before" callWorker and "Message consumer" but it did not work,
I also tried camunda.bpm.database.jdbc-batch-processing=false and got the same results,
I tried also parallel branches but i get OptimisticLocak exception and MismatchingMessageCorrelationException
Maybe i am doing it wrong
Thanks for your help
This is an interesting problem. As you already found out, the error happens, when you try to correlate the result from the "worker" before the main process ended its transaction, thus there is no message subscription registered at the time you correlate.
This problem in process orchestration is described and analyzed in this blog post, which is definitely worth reading.
Taken from that post, here is a design that should solve the issue:
You make message send and receive parallel and put an async before the send task.
By doing so, the async continuation job for the send event and the message subscription are written in the same transaction, so when the async message send executes, you already have the subscription waiting.
Although this should work and solve the issue on BPMN model level, it might be worth to consider options that do not require remodeling the process.
First, instead of calling the worker directly from your delegate, you could (assuming you are on spring boot) publish a "CallWorkerCommand" (simple pojo) and use a TransactionalEventLister on a spring bean to execute the actual call. By doing so, you first will finish the BPMN process by subscribing to the message and afterwards, spring will execute your worker call.
Second: you could use a retry mechanism like resilience4j around your correlate message call, so in the rare cases where the result comes to quickly, you fail and retry a second later.
Another solution I could think of, since you seem to be using an "external worker" pattern here, is to use an external-task-service task directly, so the send/receive synchronization gets solved by the Camunda external worker API.
So many options to choose from. I would possibly prefer the external task, followed by the transactionalEventListener, but that is a matter of personal preference.

Usage of send and receive task in camunda BPMN

I am using a send task to which the following Javadelegate class is attached.
public class SendTaskDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
execution.getProcessEngineServices()
.getRuntimeService()
.createMessageCorrelation("someMessage")
.processInstanceBusinessKey("someBusinessKey")
.correlate();
}
}
But I am getting this error::
An error happend while submitting the task form : Cannot submit task form c0e85bad-719f-11e5-94aa-d897baecf24a: Cannot correlate message someMessage: No process definition or execution matches the parameters
How can I debug it?
The error message says, that your JavaDelegate code just gets excuted correctly. The process engine tries to find a running process instance with 'someBusinessKey' as business key and currently waiting for a message 'someMessage', but does not find such an instance. Your code acts as if there were such an instance and you try to find it and tell it about a message. See the docs section about correlation methods - in principle the mechanism is used to 'route' a message to the correct instance targeting it.
As a sidenote: your JavaDelegate seems to get called in the same transaction with which you also try to complete a task. The "borders of transactions" in your process can be managed with 'async' attributes described in the docs section about transactions in processes.

Thread Safety in Jax-WS Request-Response Payload Logging

I am working on a SoapHandler implementation. Basically my aim is to get both request and response payloads and insert them to the database.
Although I can get the request and response payloads, I couldn't make sure if my code is working thread-safe. In other words, I am not sure if responses match with the proper requests.
public boolean handleMessage(SOAPMessageContext mContext) {
boolean isResponse = (Boolean) mContext
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!isResponse) {
try {
mContext.put("currentStream", new ByteArrayOutputStream());
mContext.getMessage().writeTo((OutputStream) mContext.get("currentStream"));
} catch (SOAPException | IOException e) {
e.printStackTrace();
}
} else {
try {
mContext.getMessage().writeTo(
(OutputStream) mContext.get("currentStream"));
System.out.println(((OutputStream) mContext.get("currentStream"))
.toString());
((OutputStream) mContext.get("currentStream")).flush();
} catch (SOAPException | IOException e) {
e.printStackTrace();
}
}
return true;
}
I found this in JCP specs:
9.3.3 Handler Implementation Considerations
Handler instances may be pooled by a JAX-RPC runtime system. All instances of a specific handler are
considered equivalent by a JAX-RPC runtime system and any instance may be chosen to handle a particular
message. Different handler instances may be used to handle each messages of an MEP. Different threads
may be used for each handler in a handler chain, for each message in an MEP or any combination of the
two. Handlers should not rely on thread local state to share information. Handlers should instead use the
message context, see section 9.4.
9.4 Message Context
Handlers are invoked with a message context that provides methods to access and modify inbound and
outbound messages and to manage a set of properties.
Different types of handler are invoked with different types of message context. Sections 9.4.1 and 9.4.2
describe MessageContext and LogicalMessageContext respectively. In addition, JAX-RPC bindings 12
may define a message context subtype for their particular protocol binding that provides access to protocol
specific features. Section10.3 describes the message context subtype for the JAX-RPC SOAP binding.
http://download.oracle.com/otn-pub/jcp/jaxrpc-2.0-edr2-spec-oth-JSpec/jaxrpc-2_0-edr2-spec.pdf?AuthParam=1431341511_1ac4403a34d7db108bce79eda126df49
Does this imply that a new MessageContext object is created for each request (in which case I think the code will be thread safe), or the same MessageContext object can be used for multiple requests (then my code will not be thread safe).
Any help / alternative solution will be appreciated.
Rule of thumb: a FooContext object is contextual by definition, relating to a specific execution context. EJBContext relating to a single EJB; FacesContext relating to a single Faces request context; SOAPMessageContext relating to a single SOAPMessage. From the JSR-109 documentation:
The container must share the same MessageContext instance across all Handler instances and the target endpoint that are invoked during a single request and response or fault processing on a specific node.
So, you can be sure that there's one new SOAPMessageContext instance per request. Within the context of a single request however, that instance is yours to mangle. So the question really is, what do you mean by "threadsafety"? Do you plan to have multiple threads processing a single SOAPMessageContext during each request? I don't recommend it
EDIT: While the specification doesn't state in black and white that a MessageContext is threadsafe, it's implied throughout the specification. The following is an excerpt from the section of the spec that states what's possible on a MessageContext, within a handler:
Handlers may manipulate the values and scope of properties within the message context as desired. E.g. ... a handler in a server-side SOAP binding might add application scoped properties tot he message context from the contents of a header in a request SOAP message...
SOAP handlers are passed a SOAPMessageContext when invoked. SOAPMessageContext extends MessageContext with methods to obtain and modify the SOAP message payload
The specification won't be expecting programmers to modify the content of the context if it weren't safe to do so.