Esper. Unable to receive remove events in listeners - event-handling

When using Time windows in Esper, the old or removed events from the window is sent as output to UpdateListener attached to the statement. This is what should be occurring according to the document. But when I execute the code like below, it doesn't has any events in oldEvents even a new sliding window starts. It even happens with length window.
EPStatement statement1 = epAdmin.createEPL("select current_timestamp, sum(price)" + " from StockTick.win:time(5 sec)");
statement1.addListener(new UpdateListener() {
#Override
public void update(EventBean[] newEvents, EventBean[] oldEvents) {
System.out.println("sum \t" + newEvents[0].getUnderlying() + "\n");
System.out.println("old sum \t" + oldEvents[0].getUnderlying() + "\n");
}
});
When I send events into this query, the UpdateListener gets newEvents entering into windows in newEvents but when a event is removed from further sliding windows, it should be present in oldEvents but I did not get any events into it.
Is there any mistake I am doing while constructing listeners or statements.

By default engine does not output remove stream unless the select clause has "irstream".
select irstream current_timestamp, ....

Related

Trigger Beam ParDo at window closing only

I have a pipeline that read events from Kafka. I want to count and log the event count only when the window closes. By doing this I will only have one output log per Kafka partition/shard on each window. I use a timestamp in the header which I truncate to the hour to create a collection of hourly timestamps. I group the timestamps by hour and I log the hourly timestamp and count. This log will be sent to Grafana to create a dashboard with the counts.
Below is how I fetch the data from Kafka and where it defines the window duration:
int windowDuration = 5;
p.apply("Read from Kafka",KafkaIO.<byte[], GenericRecord>read()
.withBootstrapServers(options.getSourceBrokers().get())
.withTopics(srcTopics)
.withKeyDeserializer(ByteArrayDeserializer.class)
.withValueDeserializer(ConfluentSchemaRegistryDeserializerProvider
.of(options.getSchemaRegistryUrl().get(), options.getSubject().get()))
.commitOffsetsInFinalize())
.apply("Windowing of " + windowDuration +" seconds" ,
Window.<KafkaRecord<byte[], GenericRecord>>into(
FixedWindows.of(Duration.standardSeconds(windowDuration))));
The next step in the pipeline is to produce two collections from the above collection one with the events as GenericRecord and the other with the hourly timestamp, see below. I want a trigger (I believe) to be applied only two the collection holding the counts. So that it only prints the count once per window. Currently as is, it prints a count every time it reads from Kafka creating a large number of entries.
tuplePCollection.get(createdOnTupleTag)
.apply(Count.perElement())
.apply( MapElements.into(TypeDescriptors.strings())
.via( (KV<Long,Long> recordCount) -> recordCount.getKey() +
": " + recordCount.getValue()))
.apply( ParDo.of(new LoggerFn.logRecords<String>()));
Here is the DoFn I use to log the counts:
class LoggerFn<T> extends DoFn<T, T> {
#ProcessElement
public void process(ProcessContext c) {
T e = (T)c.element();
LOGGER.info(e);
c.output(e);
}
}
You can use the trigger “Window.ClosingBehavior”. You need to specify under which conditions a final pane will be created when a window is permanently closed. You can use these options:
FIRE_ALWAYS: Always Fire the last Pane.
FIRE_IF_NON_EMPTY: Only Fire the last pane if there is new data since
previous firing.
You can see this example.
// We first specify to never emit any panes
.triggering(Never.ever())
// We then specify to fire always when closing the window. This will emit a
// single final pane at the end of allowedLateness
.withAllowedLateness(allowedLateness, Window.ClosingBehavior.FIRE_ALWAYS)
.discardingFiredPanes())
You can see more information about this trigger.

MIKMIDI: writing events on a track produces a warning

I'm trying to write a program to shift the key of a midi file. Basically, I just need to shift every note event by a given amount and live the rest unchanged. I found it easy to use MIKMIDI to read, parse, modify and write back the stream.
Unfortunately, I have a problem that I'm unable to solve. I've a loop in which I select the note events and add/subtract the desired shift value, but when I append the event in the output track I get a message from the MIKMIDI library:
"Warning: attempted to insert a NULL event".
The code I wrote is the following:
for event in inputTrack.events {
if event.eventType == .midiNoteMessage {
var tmpData = event.data
if (event.data[0] != 9) { // skip percussion channel
tmpData[1] = event.data[1] - shift
}
let outEvent = MIKMIDIEvent(timeStamp: event.timeStamp, midiEventType: .midiNoteMessage, data: tmpData)!
outputSeq.tracks[i].events.append(outEvent)
}
else {
outSeq.tracks[i].events.append(event)
}
}
BTW, the code works perfectly (the midi file is plays as expected), it is just that it takes minutes to execute in debugging mode due to the infinite sequence of warning messages printed in the debug screen.
Thanks!

Wix: Populate repeater with external API call

I'm referring to the following video How to Create A Web App With External API Access using Wix Code & wanted to know how I would populate a repeater rather than populating a paragraph tag as shown in the youtube video mentioned above.
Basically here is the pseudocode of what I would like to achieve:
If search box is equal to null or empty
Display all crypto currencie(s)
else
Display single crypto currency
Putting the info in a repeater isn't too different than what the example already shows. Actually, when the search box is empty, the API returns an array that just needs a little playing with to get it to work with a repeater.
So, assuming you added a repeater with the ID repeater1 that contains a text element with the id result, you can make the following minor changes to the page code. You don't need to touch the backend code at all.
First, in the button1_click event handler we'll remove the code that populates the text element with the data returned from the API. Instead, we'll add an _id property to each currency object (required for the repeater) and then feed that data to the repeater.
export function button1_click(event) {
getCryptoCurrencyInfo($w("#currencyInput").value)
.then(currencyInfo => {
// add an _id property to each currency object
currencyInfo.forEach(item => item._id = item.id);
// feed the data to the repeater
$w('#repeater1').data = currencyInfo;
} );
}
Then, we can take the code for populating the text element and stick it in the repeater1_itemReady event handler. This function will run once for each currency item in the array fed to the repeater's data property. Make sure you use the properties panel to wire the function to the matching repeater event.
export function repeater1_itemReady($item, itemData, index) {
$item("#result").text = "Name: " + itemData.name + "\n"
+ "Symbol: " + itemData.symbol + "\n"
+ "Rank: " + itemData.rank + "\n"
+ "Price (USD): " + itemData.price_usd + "\n"
+ "Market Capitalization (USD): " + itemData.market_cap_usd + "\n"
+ "Percent Change 1h: " + itemData.percent_change_1h + "\n"
+ "Percent Change 24h: " + itemData.percent_change_24h + "\n"
+ "Percent Change 7d: " + itemData.percent_change_7d;
}
Notice two subtle changes to the code. First, we use $item instead of $w to select the text element. This selects the specific instance of the text element in the current repeater element. Second, we use itemData instead of currencyInfo[0]. This gives us the specific data that is associated with the current repeater element.

Does setValueAtTime has a specific duration?

In the docs says:
The setValueAtTime() method of the AudioParam interface schedules an instant change to the AudioParam value at a precise time, as measured against AudioContext.currentTime. The new value is given in the value parameter.
From what one can think it makes an instant change but when a run this code
...
biquadNode.gain.setValueAtTime(12, this._AudioContext.currentTime);
console.log("biquadNode.gain " + biquadNode.gain.value);
console.log("biquadNode.frequency " + biquadNode.frequency.value);
setTimeout(() => {
console.log("biquadNode.gain " + biquadNode.gain.value);
console.log("biquadNode.frequency " + biquadNode.frequency.value);
}, 100);
...
It outputs:
0
12
I am not sure why...
It's instant, right, yet asynchronous (and is assumed to be a non-blocking op), as it's executed in a separate thread - note the word schedules in the description. That's why you won't see the change immediately.
Note that another method of updating value, via direct assignment to the corresponding property...
biquadNode.gain.value = 12;
... isn't synchronous either - and is basically equivalent to setValueAtTime(newValue, currentTime), as explained in this issue.

Firing Maximo workflow event from code

In our Maximo workflow we have a few schemas in which work order reaches a Condition node with a check on a startdate. If current date is less than it's startdate then work order goes to a Wait node with "maximo.workorder.update" condition. So when the scheduled date for WO comes people need to go to WO tracking and save this WO manually. Only then it continues it's way through the workflow. Otherwise WO will sit on that Wait node till the end of time.
What I want to do is to trigger this update event by crontask everyday so when the right date comes WO will wake up by itself.
I inspected source code for a Save button in WO tracking application and found that no matter what there's MboRemoteSet.save() method call. I assumed that you need to get some changes done and then call save() on the right MboSet. Also I know that in DB there's table called EVENTRESPONSE that keeps track of WOs sitting on the Wait nodes in workflow.
My crontask class contains this code:
MXServer mxServer = MXServer.getMXServer();
UserInfo userInfo = mxServer.getUserInfo("maxadmin");
woSet = mxServer.getMboSet("WORKORDER", userInfo);
...
String query = "select sourceid as WORKORDERID from EVENTRESPONSE"
+ " where eventname = 'maximo.workorder.update'"
+ " and sourcetable = 'WORKORDER'";
SqlFormat sqf = new SqlFormat("workorderid IN (" + query + ")");
woSet.setWhere(sqf.format());
MboRemote wo;
Date currentDate = new Date();
for (int i = 0; (wo = woSet.getMbo(i)) != null; i++) {
System.err.println(wo.getString("description"));
wo.setValue("CHANGEDATE", currentDate);
}
woSet.save();
workorder.changedate successfully refreshes but "maximo.workorder.update" event doesn't proc and WO stays on the Wait node.
So, how should I fire maximo.workorder.update?
This response comes a year late, I understand, but it may help others.
It is possible to use an "Escalation" to identify all work orders that have had their time to come and use an action on the escalation to update something on the work order. This will result in Maximo saving the change, thereby triggering the wait node of the workflow, all without any code, just configurations.
I have done something similar in the past and usually I end up flipping a YORN field that I had created for this purpose.