I am trying to implement the guaranteed message processing but the ack or fail methods on the Spout are not being called.
I am passing the a message ID object with the spout.
I am passing the tuple with each bolt and calling collector.ack(tuple) in each bolt.
Question
The ack or fail is not being called and I cannot work out why?
Here is a shortened code sample.
Spout Code using BaseRichSpout
public void nextTuple() {
for( String usage : usageData ) {
.... further code ....
String msgID = UUID.randomUUID().toString()
+ System.currentTimeMillis();
Values value = new Values(splitUsage[0], splitUsage[1],
splitUsage[2], msgID);
outputCollector.emit(value, msgID);
}
}
#Override
public void ack(Object msgId) {
this.pendingTuples.remove(msgId);
LOG.info("Ack " + msgId);
}
#Override
public void fail(Object msgId) {
// Re-emit the tuple
LOG.info("Fail " + msgId);
this.outputCollector.emit(this.pendingTuples.get(msgId), msgId);
}
Bolt Code using BaseRichBolt
#Override
public void execute(Tuple inputTuple) {
this.outputCollector.emit(inputTuple, new Values(serverData, msgId));
this.outputCollector.ack(inputTuple);
}
Final Bolt
#Override
public void execute(Tuple inputTuple) {
..... Simply reports does not emit .....
this.outputCollector.ack(inputTuple);
}
The reason the ack did not work was the use of the for loop in the spout. Changed this to a counter loop version below the emit and it works.
Example
index++;
if (index >= dataset.size()) {
index = 0;
}
Further to this thanks to the mailing list info.
Its because the Spout runs on a single thread and will block in a for loop, as next tuple will not return therefore it will never be able to call ACK method.
Related
I'm working on state processing function where im keying on an ID and would like to hold a state for like 60 secs.
DataStream<String> keyedStream = stream.keyBy(Events::getAnonymousId)
.process(new KeyedProcessingWithCallBack(Long.parseLong(parameters.get("ttl"))))
.uid("keyed-processing");
keyedStream.sinkTo(sink(parameters))
.uid("kafka-sink");
public class KeyedProcessingWithCallBack extends KeyedProcessFunction<String, Events, String> {
ValueState<Boolean> anonymousIdHasBeenSeen;
private final long stateTtl;
public KeyedProcessingWithCallBack(long stateTtl) {
this.stateTtl = stateTtl;
}
#Override
public void open(Configuration parameters) throws Exception {
ValueStateDescriptor<Boolean> desc = new ValueStateDescriptor<>("anonymousIdHasBeenSeen", Types.BOOLEAN);
// defines the time the state has to be stored in the state backend before it is auto cleared
anonymousIdHasBeenSeen = getRuntimeContext().getState(desc);
}
#Override
public void processElement(EngagerEvents value, KeyedProcessFunction<String, Events, String>.Context ctx, Collector<String> out) throws Exception {
if (anonymousIdHasBeenSeen.value() == null) {
System.out.println("Value is NULL : " +value.getAnonymousId());
// key is not available in the state
anonymousIdHasBeenSeen.update(true);
System.out.println("TIMER START TIME: " +ctx.timestamp());
ctx.timerService().registerProcessingTimeTimer(ctx.timestamp() + (stateTtl * 1000));
out.collect(value.getEventString());
}
}
#Override
public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out)
throws Exception {
// triggers after ttl has passed
System.out.println("Call back triggered : time : " +timestamp + " value : " +anonymousIdHasBeenSeen.value());
if (anonymousIdHasBeenSeen.value()) {
anonymousIdHasBeenSeen.clear();
}
}
I have registered a timer to clear value from state. however as per my logs it is triggering correctly. but my process element is accepting the value for the same key before even it is cleared in the call back.
Expect data in the output topic are separated by a minute gap, but is not.
Can someone point out the mistake in my implementation here. I'm spanning multiple threads to pump request at the same time.
I am not familiar with JAVA and struggling for days now understanding one particular issue.
I want to receive messages from the Azure Cloud and I am using the Azure-Service-Bus.
According to azure-service-bus documentation I have build a java file which looks like this:
import com.azure.messaging.servicebus.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.Arrays;
import java.util.List;
static String connectionString = "<NAMESPACE CONNECTION STRING>";
static String topicName = "<TOPIC NAME>";
static String subName = "<SUBSCRIPTION NAME>";
// handles received messages
static void receiveMessages() throws InterruptedException
{
CountDownLatch countdownLatch = new CountDownLatch(1);
// Create an instance of the processor through the ServiceBusClientBuilder
ServiceBusProcessorClient processorClient = new ServiceBusClientBuilder()
.connectionString(connectionString)
.processor()
.topicName(topicName)
.subscriptionName(subName)
.processMessage(ServiceBusTopicTest::processMessage)
.processError(context -> processError(context, countdownLatch))
.buildProcessorClient();
System.out.println("Starting the processor");
processorClient.start();
TimeUnit.SECONDS.sleep(10);
System.out.println("Stopping and closing the processor");
processorClient.close();
}
private static void processMessage(ServiceBusReceivedMessageContext context) {
ServiceBusReceivedMessage message = context.getMessage();
System.out.printf("Processing message. Session: %s, Sequence #: %s. Contents: %s%n", message.getMessageId(),
message.getSequenceNumber(), message.getBody());
}
private static void processError(ServiceBusErrorContext context, CountDownLatch countdownLatch) {
System.out.printf("Error when receiving messages from namespace: '%s'. Entity: '%s'%n",
context.getFullyQualifiedNamespace(), context.getEntityPath());
if (!(context.getException() instanceof ServiceBusException)) {
System.out.printf("Non-ServiceBusException occurred: %s%n", context.getException());
return;
}
ServiceBusException exception = (ServiceBusException) context.getException();
ServiceBusFailureReason reason = exception.getReason();
if (reason == ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED
|| reason == ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND
|| reason == ServiceBusFailureReason.UNAUTHORIZED) {
System.out.printf("An unrecoverable error occurred. Stopping processing with reason %s: %s%n",
reason, exception.getMessage());
countdownLatch.countDown();
} else if (reason == ServiceBusFailureReason.MESSAGE_LOCK_LOST) {
System.out.printf("Message lock lost for message: %s%n", context.getException());
} else if (reason == ServiceBusFailureReason.SERVICE_BUSY) {
try {
// Choosing an arbitrary amount of time to wait until trying again.
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.err.println("Unable to sleep for period of time");
}
} else {
System.out.printf("Error source %s, reason %s, message: %s%n", context.getErrorSource(),
reason, context.getException());
}
}
public static void main(String[] args) throws InterruptedException {
receiveMessages();
}
Everything works well so far and the messages from Azure are printed in the console-log.
Nevertheless my goal is to save the messages in a variable/array-list which I want to create in the main() function. So I tried to return the messages in the processMessage() function to the main() function, but it doesn't work since it is a static void class. I also tried to create an array-list variable and pass it to the processMessage() function, but I didn't get how to pass the array-list variable in the processClient creation.
I am using a Low-Code Plattform called Mendix and want to implement this custom java code and just struggling with passing the messages in to an array-list to the main() function.
Can someone help me or give me a hint how to solve this issue?
Thanks,
Ă–mer
So I tried to return the messages in the processMessage() function to
the main() function, but it doesn't work since it is a static void
class.
Since you want to get the message in a variable type or a array list type, then just make the return type as below:
public static void main(String args[]){
System.out.println("---------This is the returnString()---------");
System.out.println(returnString());
System.out.println("---------This is the returnArrayList()---------");
System.out.println(returnArrayList());
}
public static String returnString(){
//For example is the message you get.
String message = "some message";
return message;
}
public static ArrayList returnArrayList(){
//For example is the message you get.
ArrayList<String> arlist = new ArrayList<String>( );
arlist.add("JAVA");
arlist.add("Csharp");
arlist.add("Python");
arlist.add("Php");
arlist.add("Android");
arlist.add("HTML");
return arlist;
}
Problem statement:- I am trying to automate a MQTT flow, for that I a need to publish and subscribe to multiple topics but in a sequential order. The trick part is that the message received from the first publish has some value which will be passed in the next sub/pub commands.
For eg.
Sub to topicA/abc
Pub to topicA/abc
Message received on topicA/abc is xyz
sub to topic topicA/xyz
pub to topic topicA/xyz
I am able to receive the message on the first topic but I am not getting how to access the payload of the received message in the main method and pass and attach it to the next topic for next sub.
Is there a way to get the retrieved the message payload from messageArrived callback method to the main method where is client instance is created?
Note:- I am using a single client for publish and subscribe.
kindly help me out as I have ran out of options and methods to do so.
Edited:-
Code snippet
Main class
public class MqttOverSSL {
String deviceId;
MqttClient client = null;
public MqttOverSSL() {
}
public MqttOverSSL(String deviceId) throws MqttException, InterruptedException {
this.deviceId = deviceId;
MqttConnection mqttConObj = new MqttConnection();
this.client = mqttConObj.mqttConnection();
}
public void getLinkCodeMethod() throws MqttException, InterruptedException {
client.subscribe("abc/multi/" + deviceId + "/linkcode", 0);
publish(client, "abc/multi/" + deviceId + "/getlinkcode", 0, "".getBytes());
}
}
Mqtt Claback impl:-
public class SimpleMqttCallBack implements MqttCallback {
String arrivedMessage;
#Override
public void connectionLost(Throwable throwable) {
System.out.println("Connection to MQTT broker lost!");
}
#Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
arrivedMessage = mqttMessage.toString();
System.out.println("Message received:\t" + arrivedMessage);
linkCode(arrivedMessage);
}
#Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("Delivery complete callback: Publish Completed "+ Arrays.toString(iMqttDeliveryToken.getTopics()));
}
public void linkCode(String arrivedMessage) throws MqttException {
System.out.println("String is "+ arrivedMessage);
Gson g = new Gson();
GetCode code = g.fromJson(arrivedMessage, GetCode.class);
System.out.println(code.getLinkCode());
}
}
Publisher class:-
public class Publisher {
public static void publish(MqttClient client, String topicName, int qos, byte[] payload) throws MqttException {
String time = new Timestamp(System.currentTimeMillis()).toString();
log("Publishing at: "+time+ " to topic \""+topicName+"\" qos "+qos);
// Create and configure a message
MqttMessage message = new MqttMessage(payload);
message.setQos(qos);
// Send the message to the server, control is not returned until
// it has been delivered to the server meeting the specified
// quality of service.
client.publish(topicName, message);
}
static private void log(String message) {
boolean quietMode = false;
if (!quietMode) {
System.out.println(message);
}
}
}
OK, it's a little clearer what you are trying to do now.
Short answer No, you can not pass values back to the "main method". MQTT is asynchronous that means you have no idea when a message will arrive for a topic you subscribe to.
You need to update your code to deal check what the incoming message topic is and then deal do what ever action you wanted to do with that response in the messageArrived() handler. If you have a sequence of task to do then you may need to implement what is known as a state machine in order to keep track of where you are in the sequence.
I am trying to implement a CoAP client based on Californium. I make this client observing to a resource:
public static class CoapCl{
double val = 0;
CoapClient client = new CoapClient("coap://localhost/Ultrasonic");
CoapObserveRelation relation = client.observe(new CoapHandler() {
#Override public void onLoad(CoapResponse response)
{
val = Double.parseDouble(response.getResponseText());
}
#Override
public void onError() {
System.out.println("Failed");
}
});
}
I want to access the value "val" from another class. How can I do it ? I tried to call a reference from the CoapCl class like this and print the value out:
CoapCl client = new CoapCl();
while(true)
{
System.out.println("Testing: " + client.val);
}
This will print all the value I get from the CoAP client, both changed and unchanged value. What should I do if I only want to get the changed value ?
Well, the issue itself isn't related to Californium and CoAP.
Except that CoapHandler is async but this is rather a strench.
Nevertheless, I'd recommend to end up with some kind of callback:
public class CoapCl {
private final Consumer<Double> valueChangedAction;
private final CoapClient client = new CoapClient("coap://localhost/Ultrasonic");
public CoapCl(Consumer<Double> valueChangedAction) {
this.valueChangedAction = valueChangedAction;
}
public void run() {
client.observe(new CoapHandler() {
#Override
public void onLoad(CoapResponse response) {
valueChangedAction.accept(
Double.parseDouble(
response.getResponseText()
)
);
}
#Override
public void onError() {
System.out.println("Failed");
}
});
}
}
new CoapCl(val -> System.out.println("Testing: " + val)).run();
Please keep in mind you have to block the main thread someway to keep the program from immediate exit.
Before, you had blocked it with your infinite loop.
Now you'll have to use System.in.read() or Thread.sleep or something else if you have no such stuff yet in your program.
I have an utility class from which I am calling a service api. If everything is fine I will get desired output which is in string format.So that's success case. But It may happen that I get an error suppose 404 if the server is down.In such cases I want to call that api for suppose 3 times with 1 second interval between them. If within these three retries I get success from the Api then I will not cal the api and log the result, Or if after 3 retries it still throws error then I will not continue and just log the error.
my Utility class
public class Utils {
public void doOperation(String service_Url) throws Exception {
Object message= someFunction(service_Url);//this function is calling the service api
final ActorSystem system = ActorSystem.create("helloakka");
final ActorRef akkaBot=system.actorOf(Props.create(MyUntypedActor.class), "akkaBot");
akkaBot.tell(message, ActorRef.noSender());
}
}
Here is the Actor
public class MyUntypedActor extends UntypedActor {
#Override
public void onReceive(Object message) {
if (message instanceof HTTPException) {
System.out.println(message);
//Here as it got exception.I want to call the actor 3 times with 1 second interval between them
}
else if (message instanceof String) {
System.out.println(message);
getSender().tell(value, getSelf());
}
else {
unhandled(message);
}
}
}
The objective is test a particular api is working or not using akka actor.If the api returns exception then call that api using actor 3 times with 1 sec interval between each call.If after 3 times we are still getting error then then log the error,if while retrying we get desired output then log it.
I don't know how to achieve it using akka actors.Please guide me if you know.
What you are asking for can be accomplished with a slight modification of your code organization. It would be easier for your Actor to do all of the querying rather than just the queries subsequent to a failure.
You'll first need some way of representing the failures:
public class RequestFailure {
public String request;
public int count;
public RequestFailure(String r, int c) {
request = r;
count = c;
}
}
This class can then be a message type sent to your Actor which will act accordingly:
public class MyUntypedActor extends UntypedActor {
public void onReceive(Object message) {
if(message instanceOf String) {
Object response = someFunction( (String) message);
if(response instanceOf HTTPException) {
Thread.sleep(1000);
getSelf().tell(new RequestFailure((String) message, 1), getSender());
}
else
getSender().tell(response, getSelf())
}
else if(message instanceOf RequestFailure) {
RequestFailure rf = (RequestFailure) message;
if(rf.count <= 3) {
Object response = someFunction(rf.request);
if(response instanceOf HTTPException) {
Thread.sleep(1000);
getSelf().tell(new RequestFailure(rf.request, rf.count + 1), getSender();
}
else
getSender().tell(response, getSelf())
}
}
else
//FIXME : question doesn't specify what to return
// if max count reached
}
}
}
You would then ask the Actor with a request String to start the process.