I am using Ignite cache with ModifiedExpiryPolicy and need to execute a line of code before event execution. Any help?
IgniteCache<String, Object> expiresCache = cache.withExpiryPolicy(new ModifiedExpiryPolicy(new Duration(Time.MINUTES, timeInMins)));
public class ClassName {
public IgnitePredicate<CacheEvent> functionName() {
return new IgnitePredicate<CacheEvent>() {
#Override
public boolean apply(CacheEvent evt) {
//code to be executed after event.
return true;
}
};
}
}
I think you need to use events to listen for expiry events.
Ignite ignite = Ignition.ignite();
// Local listener that listenes to local events.
IgnitePredicate<CacheEvent> locLsnr = evt -> {
System.out.println("Received expiry event [evt=" + evt.name() + ", key=" + evt.key());
return true; // Continue listening.
};
// Subscribe to specified cache events occuring on local node.
ignite.events().localListen(locLsnr, EventType.EVT_CACHE_OBJECT_EXPIRED);
Note that this is just a local (node) listener, you'll need a remote listener to find expiry events on remote nodes. You'll also need to configure includeEventTypes in your configuration file (events are disabled by default for performance reasons.
Related
I have a producer, which send more than 1000 messages in a minute to a specific endpoint. I’m using Microsoft DI and I’ve configured the send Endpoint as described here https://masstransit-project.com/usage/producers.html#send .
// Masstransit setup
serviceCollection.AddMassTransit(mt =>
{
mt.UsingAzureServiceBus((ctx, cfg) =>
{
cfg.Host(massTransitSettings.TestServiceBusConnectionString);
cfg.ReceiveEndpoint("mytestmessage", e =>
{
e.MaxDeliveryCount = 3; //How many times the transport will redeliver the message on negative acknowledgment
});
});
});
serviceCollection.AddTransient<ITestMessageProducer, TestMessageProducer>();
// Producer setup
public class TestMessageProducer : ITestMessageProducer
{
private readonly ISendEndpointProvider _testEndpoint;
public TestMessageProducer(ISendEndpointProvider testEndpoint)
{
_testEndpoint = testEndpoint;
}
public async Task SendTestMessage(ITestMessage testmessage)
{
var endpoint = await _testEndpoint.GetSendEndpoint(new Uri("queue:mytestmessage"));
await endpoint.Send(testmessage);
}
}
Query:
The SendTestMessage function has been called very frequently as mention above. Will it be ok to call “GetSendEndpoint” everytime? I have read somewhere that GetSendEndpoint creates a new instance of ISendEndpoint everytime.
Will the MaxDeliveryCount still be worked on my sendendpoint?
Thank you.
Send endpoints are cached by address, only a single instance will be created.
MaxDeliveryCount is a receive endpoint concern, but you should not configure a receive endpoint without consumers as all messages will be moved to the _skipped queue.
I am currently using the Event Store to handle my events. I currently need to replay a particular type of event as I have made changes in the way they are subscribed and written to DB.
Is this possible? If so, how can it be done? Thanks.
You cannot tell EventStore to replay a specific event onto a persistent subscription because the point of the persistent subscription is to keep state for the subscribers.
To achieve this kind of fix you would really need a catch up application to do the work.
And really if you think about, if you replayed ALL the events to a new database then you would have the correct data in there?
So I have a console application that reuses the same logic as the persistent connection but the only difference is:
I change the target database connection string - So this would be a new Database or Collection (not the broken one)
It connects to EventStore and replays all the events from the start
It rebuilds the entire database to the correct state
Switch the business over to the new database
This is the point of EventStore - You just replay all the events to build any database at any time and it will be correct
Your persistent connections deal with new, incoming events and apply updates.
If you enable $by_event_type projection than you can access that projection stream under
/streams/$et-{event-type}
https://eventstore.org/docs/projections/system-projections/index.html
Then you can read it using .net api if you wish.
Here is some code to get you started
private static T GetInstanceOfEvent<T>(ResolvedEvent resolvedEvent) where T : BaseEvent
{
var metadataString = Encoding.UTF8.GetString(resolvedEvent.Event.Metadata);
var eventClrTypeName = JObject.Parse(metadataString).Property(EventClrTypeHeader).Value;
var #event = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(resolvedEvent.Event.Data), Type.GetType((string) eventClrTypeName));
if (!(#event is BaseEvent))
{
throw new MessageDeserializationException((string) eventClrTypeName, metadataString);
}
return #event as T;
}
private static IEventStoreConnection GetEventStoreConnection()
{
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["EventStore"].ConnectionString;
var connection = EventStoreConnection.Create(connectionString);
connection.ConnectAsync().Wait();
return connection;
}
private static string GetStreamName<T>() where T : BaseEvent
{
return "$et-" + typeof(T).Name;
}
And to read events you can use this code snippet
StreamEventsSlice currentSlice;
long nextSliceStart = StreamPosition.Start;
const int sliceCount = 200;
do
{
currentSlice = await esConnection.ReadStreamEventsForwardAsync(streamName, nextSliceStart, sliceCount, true);
foreach (var #event in currentSlice.Events)
{
var myEvent = GetInstanceOfEvent<OrderMerchantFeesCalculatedEvent>(#event);
TransformEvent(myEvent);
}
nextSliceStart = currentSlice.NextEventNumber;
} while (currentSlice.IsEndOfStream == false);
I'm new to JMS and am trying to setup Apache Active MQ for a messaging application as an alternative to Azure Service Bus that I'm very familiar with. I would like to setup topics and durable subscribers as and administrative task, and would like the runtime process to consume messages from those existing durable subscriber only based upon its name and, possibly, client id.
How do I retrieve an existing durable subscriber, without knowing the selector?
All the documentation and the samples I've read show that the only way to consume a message is to call the session.createDurableSubscriber() method.
Additionaly, I prefer to use the AMQP abstraction over JMS. So I found the following code to retrieve an existing subscriber:
public static ReceiverLink RecoverDurableSource(Session session, string topicPath, string subscriptionName)
{
Source recovered = null;
using (var attached = new ManualResetEvent(false))
{
void OnAttached(ILink link, Attach Attach)
{
recovered = (Source)Attach.Source;
attached.Set();
}
ReceiverLink receiver = null;
try
{
receiver = new ReceiverLink(session, subscriptionName, (Source)null, OnAttached);
if (!attached.WaitOne(TimeSpan.FromSeconds(5)))
return null;
CloseReceiverLink(receiver);
return recovered != null
? new ReceiverLink(session, subscriptionName, recovered, null)
: null
;
}
finally
{
if (recovered == null)
CloseReceiverLink(receiver);
}
}
}
private static void CloseReceiverLink(ReceiverLink receiver)
{
if (receiver == null)
return;
if (receiver.Error == null || Equals(receiver.Error.Condition, new Symbol("amqp:not-found")))
receiver.Close();
}
However, this code has the nasty side effect to re-create and default durable subscriber (manifested in this code by the ReceiverLink object) with the same name and then, if it exists, re-creating it with the correct Sourceobject.
But this may disrupt the reception of messages at the time this method is called.
I am using Spring + Hazelcast 3.8.2 and have configured a map like this using the Spring configuration:
<hz:map name="test.*" backup-count="1"
max-size="0" eviction-percentage="30" read-backup-data="true"
time-to-live-seconds="900"
eviction-policy="NONE" merge-policy="com.hazelcast.map.merge.PassThroughMergePolicy">
<hz:near-cache max-idle-seconds="300"
time-to-live-seconds="0"
max-size="0" />
</hz:map>
I've got two clients connected (both on same machine [test env], using different ports).
When I change a value in the map on one client the other client still has the old value until it will get evicted from the near cache due to the expired idle time.
I found a similar issue like this here: Hazelcast near-cache eviction doesn't work
But I'm unsure if this is really the same issue, at least it is mentioned that this was a bug in version 3.7 and we are using 3.8.2.
Is this a correct behaviour or am I doing something wrong? I know that there is a property invalidate-on-change, but as a default this is true, so I don't expect I have to set this one.
I also tried setting the read-backup-data to false, doesn't help.
Thanks for your support
Christian
I found the solution myself.
The issue is that Hazelcast sends the invalidations by default in batches and thus it waits a few seconds until the invalidations will be sent out to all other nodes.
You can find more information about this here: http://docs.hazelcast.org/docs/3.8/manual/html-single/index.html#near-cache-invalidation
So I had to set the property hazelcast.map.invalidation.batch.enabled to false which will immediately send out invalidations to all nodes. But as mentioned in the documentation this should only be used when there aren't too many put/remove/... operations expected, as this will then make the event system very busy.
Nevertheless, even though this property is set it will not guarantee that all nodes will directly invalidate the near cache entries. I noticed that after directly accessing the values on the different node sometimes it's fine, sometimes not.
Here is the JUnit test I built up for this:
#Test
public void testWithInvalidationBatchEnabled() throws Exception {
System.setProperty("hazelcast.map.invalidation.batch.enabled", "true");
doTest();
}
#Test
public void testWithoutInvalidationBatchEnabled() throws Exception {
System.setProperty("hazelcast.map.invalidation.batch.enabled", "false");
doTest();
}
#After
public void shutdownNodes() {
Hazelcast.shutdownAll();
}
protected void doTest() throws Exception {
// first config for normal cluster member
Config c1 = new Config();
c1.getNetworkConfig().setPort(5709);
// second config for super client
Config c2 = new Config();
c2.getNetworkConfig().setPort(5710);
// map config is the same for both nodes
MapConfig testMapCfg = new MapConfig("test");
NearCacheConfig ncc = new NearCacheConfig();
ncc.setTimeToLiveSeconds(10);
testMapCfg.setNearCacheConfig(ncc);
c1.addMapConfig(testMapCfg);
c2.addMapConfig(testMapCfg);
// start instances
HazelcastInstance h1 = Hazelcast.newHazelcastInstance(c1);
HazelcastInstance h2 = Hazelcast.newHazelcastInstance(c2);
IMap<Object, Object> mapH1 = h1.getMap("test");
IMap<Object, Object> mapH2 = h2.getMap("test");
// initial filling
mapH1.put("a", -1);
assertEquals(mapH1.get("a"), -1);
assertEquals(mapH2.get("a"), -1);
int updatedH1 = 0, updatedH2 = 0, runs = 0;
for (int i = 0; i < 5; i++) {
mapH1.put("a", i);
// without this short sleep sometimes the nearcache is updated in time, sometimes not
Thread.sleep(100);
runs++;
if (mapH1.get("a").equals(i)) {
updatedH1++;
}
if (mapH2.get("a").equals(i)) {
updatedH2++;
}
}
assertEquals(runs, updatedH1);
assertEquals(runs, updatedH2);
}
testWithInvalidationBatchEnabled finishs only sometimes successfully, testWithoutInvalidationBatchEnabled finishs always successfully.
I want to know if there is any proper way to add timer for task schedule (it will be count up) in Spring 3 + Tiles that works accurate. I have tried many options like jquery timer + (Client side) Quartz (Server side Threading), But though it is not accurate and somewhat we can say it is bad practice for web application.
What I exactly want (want to manage) is in my Web application(Spring 3 + Tiles), When user Click on Timer start, It should be started at client side and timer should be continued until user click on stop, however user could do any other things (Like navigation to any other pages) in web application but timer should be working in static way. There are many issues as if only I implement timer at client side (using cookies ,jquery session client side) than I have to manage if user navigate to another page then again timer will have to start from previous time that has been stored in cookies but doing this results in loss of seconds during request response processes.So I tried also to implement server side timer using quartz but again I have to sync it with client side timer at every click in web application . So again it is bad practice what I feel.
So Is there any thing that I can introduce in Spring 3 + tiles that can be static and can hold timer in static way.
Thanx in Advance.
Ok so you need Server Push in simple words.You can use Atmosphere for acheving this.
For integrating atmosphere with Spring MVC you can check this sample spring-web-mvc-atmosphere.after integration you just need to do this on your server side.
#RequestMapping(value = "/websockets", method = RequestMethod.GET)
#ResponseBody
public void websockets(final AtmosphereResource event) {
AtmosphereUtils.suspend(event);
final Broadcaster bc = event.getBroadcaster();
bc.scheduleFixedBroadcast(new Callable<String>() {
public String call() throws Exception {
return (new Date()).toString();
}
}, 1, TimeUnit.SECONDS);
}
And from client side:
function startTimer() {
var callbackAdded = false;
function callback(response)
{
$.atmosphere.log('info', ["response.state: " + response.state]);
$.atmosphere.log('info', ["response.transport: " + response.transport]);
if (response.transport != 'polling' && response.state != 'connected' && response.state != 'closed') {
$.atmosphere.log('info', ["response.responseBody: " + response.responseBody]);
if (response.status == 200) {
var data = response.responseBody;
if (data) {
$("#date").text(data);
}
}
}
}
$.atmosphere.subscribe("${pageContext.request.contextPath}/user/websockets",
!callbackAdded? callback : null,
$.atmosphere.request = {transport: 'websocket'});
connectedEndpoint = $.atmosphere.response;
callbackAdded = true;
};
Just suspend the get request and broadcast the current time perodically and you can extend this according to you need I have just given you a raw idea.Hope this helps.