I put Event Handler to query my events in axon framework in my spring application. I can put an event from my command up and I can read them from my query app.until reboot time no problem But when I reboot my query app Each time it reads same events again at the beginning and it cause duplicate process. How can I commit an event when I read it?
ToMyAxonConfig
#Bean
public TokenStore tokenStore(Serializer serializer, EntityManagerProvider entityManagerProvider) {
return JpaTokenStore.builder()
.entityManagerProvider(entityManagerProvider)
.serializer(serializer)
.build();
}
#Autowired
public void configureProcessors(EventProcessingConfigurer eventProcessingConfigurer) {
TrackingEventProcessorConfiguration tepConfig = TrackingEventProcessorConfiguration.forSingleThreadedProcessing().andInitialTrackingToken(StreamableMessageSource::createHeadToken);
eventProcessingConfigurer.registerTrackingEventProcessorConfiguration(config -> tepConfig);
}
I have the feeling you haven't configured a TokenStore.
In that case, Axon Framework will give you an InMemoryTokenStore implementation meaning that on every restart, you will get all Events again from your Event Store because your app does not have a 'state' for the token.
You can check the ref-guide to know more about it and also how to configure one properly from several options.
How can I commit an event when I read it?
Also to correct a bit the word usage here, Events are 'commited' on your Event Store. If you are talking about your Query Side App, you do not commit Events there but you just save a state based on Events.
Related
The main objective is to guarantee the reliability of the message delivery of our integration events in case of failures with the Application or DB, and in this scenario the new Transactional Outbox seems to be the most indicated.
With the MT Transactional Outbox, the writing (publishing) of our integration events happens atomically in the Commit of our Command Handlers.
Our solution is built as microservices that use one DB per tenant. However, the applications are shared and the DB (connection string) selection is built into the request scope.
The Outbox MT tables (OutboxMessage, In/OutboxState) are created in each tenant DB and with that we have the atomic writing of the operation along the triggering of integration events.
The problem is in the delivery to the Bus. How to make the MT background services (DeliveryService and InboxCleanupService) reach the outbox in the tenant DB, since there is no request to identify the tenant in advance?
It wouldn't be a problem if the application also runs in an environment for each tenant with their respective configuration / connection string, but that's not the case.
An alternative would be to create a third application dedicated only to running delivery/cleanup services for all tenants in separate tasks.
But to use MT delivery, we would have to dynamically create a DbContext instance (with only the Mappings for MT) for each tenant at startup. I don't know if this is the best way and it also doesn't seem possible to use the MassTransit configuration API this way.
Does anyone have an advice, approach or guide that could help us?
We were having exactly the same issue as you are describing, and we've ended up with the solution you are essentially describing yourself, a separate service that does nothing but outbox delivery and inbox cleanup.
For every MassTransit endpoint, we disable both outbox delivery and inbox cleanup
mt.AddEntityFrameworkOutbox<ContextWithOutboxTables>(outbox =>
{
var outboxConfig = outbox.UseSqlServer();
outboxConfig.DisableInboxCleanupService();
outboxConfig.UseBusOutbox(busOutbox =>
{
busOutbox.DisableDeliveryService();
});
}
and the separate service is configured similar to the below (with some code replaced/removed)
builder.ConfigureServices(s =>
{
foreach (var connectionString in distinctTenantConnectionStrings)
{
IServiceCollection outboxServices = new ServiceCollection();
outboxServices.AddDbContext<ContextWithOutboxTables>(options =>
{
options.UseSqlServer(connectionString);
});
var outboxContainer = outboxServices.BuildServiceProvider();
s.AddSingleton<IHostedService>(container =>
{
return new BusOutboxDeliveryService<ContextWithOutboxTables>(
container.GetRequiredService<IBusControl>(),
new OptionsWrapper<OutboxDeliveryServiceOptions>(new OutboxDeliveryServiceOptions()
{
// tweak your options here
}),
new OptionsWrapper<EntityFrameworkOutboxOptions>(new EntityFrameworkOutboxOptions()
{
LockStatementProvider = new SqlServerLockStatementProvider(),
// tweak your options here
}),
logger,
outboxContainer);
});
s.AddSingleton<IHostedService>(container =>
new InboxCleanupService<ContextWithOutboxTables>(new OptionsWrapper<InboxCleanupServiceOptions>(
new InboxCleanupServiceOptions()
{
// tweak your options here
}),
logger,
outboxContainer)
);
}
});
It is necessary to register the hosted service using the AddSingleton<IHostedService> override instead of AddHostedService because MS dependency injection eliminates duplicate service implementations under the covers, which is not the behavior you want, you ARE actually registering the same hosted service multiple times, with different configuration.
Creating a separate container via
IServiceCollection outboxServices = new ServiceCollection();
is necessary due to MT resolving the data context from the container, and you need it to provide a differently configured data context (connection string) for each instance of the hosted service.
Specifically what I am doing is in my AppServiceProvider->boot() method I am creating a singleton class like below:
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app->singleton('App\Support\PushNotificationHelper', function ($app) {
return new PushNotificationHelper();
});
}
}
The helper class is needed for a Queue worker job I use for Pushing Notifications to mobile apps. When the mobile device is an Apple device I need to establish a curl connection and have the connection persist beyond the life of the queue worker job. This is why I am using the singleton to hold the connection like:
class PushNotificationHelper {
protected $http2Connection;
protected $http2Expire ;
public function getConnection($options) {
$this->http2Connection = curl_init();
curl_setopt_array($this->http2Connection, $options);
return $this->http2Connection;
}
Apple claims if I connect and disconnect repeatedly then they will issue a Denial of Service (DOS). My app literally sends 1000s of notifications per hour. When ever I use the connection I check for errors and will close/reopen the connection when needed like:
curl_close($http2Connection);
However I would like to know how I can detect when the app will close for good so I can gracefully close the connection. If there is no way to do this will it harm my server over time by leaving open connections hanging, lets say months of running if the app was to start/stop several times a day ?
Another option could be is there a curl option to tell the connection to auto disconnect after so much time. (I force a close and reopen every 4 hours) so if I could tell connection to auto-close after 5 hours at least then maybe it would be self-cleaning?
IMHO you can try to add a terminating callback to your app instance, for example in the AppServiceProvider, i.e.:
public function boot()
{
$this->app->terminating(function () {
// your terminating code here
});
}
You can use the boot method for anything.
From laravel docs:
This method is called after all other service providers have been
registered, meaning you have access to all other services that have
been registered by the framework
The key is that boot method run when all services are registered, so, you can inject services in the boot method definition.
public function boot(SomeService $someService, OtherService $otherService)
{
$someService->doSomething();
$otherService->doSomething();
}
In my opinion, you must to use this method to run code required by your app in all contexts: user logged in, user logged out, post, get, put, etc., etc.
Apps handle GeoFence needs to receive PROVIDERS_CHANGED broadcast since:
Registered GeoFences will be removed when both 2 location providers
(network and GPS) are turned off.
When one of 2 location providers is turned on, app needs to register
GeoFences to work. This should be performed w/o asking user to run
my app again.
So my app has been registering its broadcast receiver in manifest. But it does not work any more in Android Oreo since PROVIDERS_CHANGED is not one we can make it work as before.
I can register broadcast receiver for that in app's activity or in service but it will quit (end its life cycle) sooner or later, then I need to unregister it. My app starts working by some events like GeoFence transition, but receiving PROVIDERS_CHANGED is critical to make it work.
I verified PROVIDERS_CHANGED can't be received by receiver registered in manifest in Android Oreo. Is there any solution for it?
#Tomcat and #Virat18 - I've come across a solution to the fact that you can no longer register a Broadcast Receiver in your Manifest to receive the PROVIDERS_CHANGED action Intent-filter in Android-OREO..
The solution? Simply register your BroadcastReceiver dynamically (from within your code), instead of from the Manifest.. Also, instead of checking for the hard-coded regex android.location.PROVIDERS_CHANGED, you should use LocationManager.PROVIDERS_CHANGED_ACTION (and of course import the LocationManager).
Here is an example of the Code I used to get this to work! (ex: from a Button Click):
public void buttonClick(View view) {
IntentFilter filter = new IntentFilter();
filter.addAction("android.location.PROVIDERS_CHANGED");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().matches(LocationManager.PROVIDERS_CHANGED_ACTION)) {
Log.i(TAG, "Action MATCHES LocationManager.PROVIDERS_CHANGED_ACTION!");
}
}
};
this.getApplicationContext().registerReceiver(receiver, filter);
Log.i(TAG, "RECEIVER HAS BEEN REGISTERED");
}
Also, don't forget to unregister the receiver in your code appropriately.
If you find this to be a good solution, please accept it as the Answer.
Happy Coding!
PS. This will continue to receive the broadcast from the background, even once the User leaves your Activity (presses the back-button, home-button, etc).. However, if the user closes your App from the Multitask button, it will no longer receive, so take note of that.
In our application which makes
use of JSF/PrimeFaces, Spring and Hibernate once a user logs in, we set a flag in the DB until the user logs out from the application or the session expires. The problem is, we need to clear this flag in the DB even when he simply closes the browser without proper logout. To acheieve this, I have already tried jquery $window.unload and $window.bind functions which actually invokes some JS function which is associated with <p:remoteCommand> which in turn invokes a managed bean method to clear the DB. However, I later came to know this is not reliable and while testing also we saw the event was not firing consistently. How can I achieve the DB cleanup anyway?
Listening on browser close is not reliable. You can use beforeunload event for that, but this is not supported on every webbrowser the world is aware of and even disableable/spoofable/hackable by the enduser. Then we're not talking about the race condition during firing the ajax request: would the ajax request arrive in its entirety right before the browser is closed? More than often this is not the case and the browser close wins over the ajax request.
Just listen server side on session expiration instead.
#WebListener
public class MyHttpSessionListener implements HttpSessionListener {
#Override
public void sessionCreated(HttpSessionEvent event) {
// NOOP.
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
// Do your job here.
// ...
}
}
Note that this is also invoked when you explicitly invoke ExternalContext#invalidateSession() (or HttpSession#invalidate()) during programmatic logout.
I've enabled Sessions support in service stack like:
container.Register<IRedisClientsManager>(c => container.Resolve<PooledRedisClientManager>());
container.Register<ICacheClient>(c => c.Resolve<IRedisClientsManager>().GetCacheClient());
container.Register<ISessionFactory>(c => new SessionFactory(c.Resolve<ICacheClient>()));
//RE: https://github.com/ServiceStack/ServiceStack/wiki/Sessions
Plugins.Add(new SessionFeature());
I see that ss-id and ss-pidd cookies are set upon visiting the site, however I would like to know when a session is started (i.e., first request from that user) so i can capture the incoming referrer url.
Using traditional asp.net sessions, i'd use Session_Start in Global, however this doesn't fire for me while using SS sessions.
Is there a good way to detect this session start event when using ServiceStack? I didn't find any reference in my queries online, or on the ServiceStack Sessions wiki.
There is currently no "Session Started" event in ServiceStack's Sessions feature, but there are some events on IAuthSession that might be useful to use instead, e.g:
public interface IAuthSession
{
...
void OnRegistered(IServiceBase registrationService);
void OnLogout(IServiceBase authService);
void OnAuthenticated(IServiceBase authService, IAuthSession session,
IOAuthTokens tokens, Dictionary<string, string> authInfo);
}
If you still would like to see an OnSessionStarted event request it as a feature in ServiceStack's GitHub issues (and include your use-case), so we can keep track of it.