I have an application (a web api) which uses DI. I have a heavy class that will process a lot of text files on startup. It needs about two minutes. I'd like for the application to get going with that as soon as it starts up, rather than when it's first called.
I have read that one should not do any heavy processing in the constructor of DI files, so what's the correct way of doing it? All my class does it provide a string in response to a string. My class unfortunately doesn't support multithreading. How can I make it thread-safe in an easy way? Performance is not a big deal for me. Make sure everything is private and make some kind of token for when it's performing a query?
Edit: I spent some time on it, and here is my Startup class. I made a 'starter' class which receives the MibLibrary class by DI and performs some starting operations on it, that seems to work reasonably well. But I'm really way out of my comfort zone here because I'm not used with DI, so I really wanna learn and take advice of what is best practice, because this will be a production service later on.
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<Appsettings>(Configuration);
services.Configure<MibLibrarySettings>(Configuration.GetSection("Appsettings.MibLibrarySettings"));
services.AddSingleton<MibLibStarter>();
services.AddSingleton<MibLibrary>();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "MibLibApi", Version = "v1" });
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, MibLibStarter mibLibStarter)
{
mibLibStarter.Start();
}
Related
In my setup I have two RabbitMQ servers that are used by different applications employing Rebus ESB. What I would like to know is if I can map a message to a queue on a different Host the way I can with MassTransit.
I also would like to know if I can send messages in a batch mode the same way with MassTransit.
Thanks In Advance.
In my setup I have two RabbitMQ servers that are used by different applications employing Rebus ESB. What I would like to know is if I can map a message to a queue on a different Host the way I can with MassTransit.
I am not sure how this works with MassTransit, but I'm pretty sure it's not readily possible with Rebus.
With Rebus, you're encouraged to treat this as you would any other integration scenario, where you'd put a ICanSendToOtherSystem in your IoC container, which just happens to be implemented by CanSendToOtherSystemUsingRebus. Your CanSendToOtherSystemUsingRebus class would probably look somewhat like this:
public class CanSendToOtherSystemUsingRebus : ICanSendToOtherSystem, IDisposable
{
readonly IBus _bus;
public CanSendToOtherSystemUsingRebus(string connectionString)
{
_bus = Configure.With(new BuiltinHandlerActivator())
.Transport(t => t.UseRabbitMqAsOneWayClient(connectionString))
.Start();
}
public Task Send(object message) => _bus.Send(message);
public void Dispose() => _bus.Dispose();
}
(i.e. just something that wraps a one-way client that can connect to that other RabbitMQ host, registered as a SINGLETON in the container)
I also would like to know if I can send messages in a batch mode the same way with MassTransit. Thanks In Advance.
Don't know how this works with MassTransit, but with Rebus, you can give the transport more convenient circumstances for optimizing the send operation(s) by using scopes:
using var scope = new RebusTransactionScope();
foreach (var message in lotsOfMessages)
{
// scope is automagically detected
await bus.Send(message);
}
await scope.CompleteAsync();
which will improve the rate with which you can send/publish with most transports. Just remember that the scope results in queuing up messages in memory before actually sending them, so you'll probably not want to send millions of messages in each batch.
I hope that answered your questions ๐
I'm migrating a WAR application from PayaraServer to Payara Micro to reduce RAM usage.
I just realise that #PreDestroy on EJBs are not called when stopping the instance with CTRL+C.
Is there a correct way to close the payaramicro instance properly as I'd like to execute some operations.
Thanks for your answers!
Or which services in Payara Server to deactivate to use as much as RAM as PayaraMicro?
I'm using the version 5.183, and I also tried the 5.192.
Which kind of EJB did you use? In my opinion it should work on #Singleton and #Stateless. I am not sure how the other EJBs are supported by Payara Micro.
However, since Payara Micro supports the Java EE Web Profile and you are using a web application anyway, I would suggest to use a #WebListener to get notified of lifecycle events.
It could be implemented as follows:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class ContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
// do needed setup work here
}
#Override
public void contextDestroyed(ServletContextEvent event) {
// do your cleanup actions here
}
}
Simply add this class to your WAR file then.
I am using the Azure Blob Storage SDK Microsoft.WindowsAzure.Storage for my ASP.NET application. I have seen some synchronous method calling asynchronous method. They use an helper method named RunWithoutSynchronizationContext from Microsoft.WindowsAzure.Storage.Core.Util.
The code is basically doing something like
SynchronizationContext current = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext((SynchronizationContext) null);
methodAsync().Wait();
}
finally
{
SynchronizationContext.SetSynchronizationContext(current);
}
I was just wondering if this is a way to avoid deadlock in .NET Framework when blocking on asynchronous code? If not, then what is it the purpose of this method?
One of the common API developer pitfalls in asynchronous development with the .Net TPL is deadlocks. Most commonly, this is caused by SDK consumers using your asynchronous SDK in a synchronous manner.
You could use ConfigureAwait(false) to avoid deadlocking. Calling this routine before awaiting a task will cause it to ignore the SynchronizationContext.
var temp = await methodAsync().ConfigureAwait(false);
However, you need to place ConfigureAwait(false) calls throughout the SDK, and it is easy to forget.
So the trick is understanding how the SynchronizationContext works. Anytime it is used, a call will be made to either itโs Send or Post method.
So, all we need to do is ensuring that these methods never get called:
public void Test_SomeActionNoDeadlock()
{
var context = new Mock<SynchronizationContext>
{
CallBase = true
};
SynchronizationContext.SetSynchronizationContext(context.Object);
try
{
context.Verify(m =>
m.Post(It.IsAny<SendOrPostCallback>(), It.IsAny<object>()), Times.Never);
context.Verify(m =>
m.Send(It.IsAny<SendOrPostCallback>(), It.IsAny<object>()), Times.Never);
}
finally
{
SynchronizationContext.SetSynchronizationContext(null);
}
}
Now we have a way to guarantee that ConfigureAwait(false) was used throughout the SDK method, so long as we get 100% test coverage through the logical paths in the method.
I am using 1.5.6.RELEASE to create REST Api that shall store user actions in MS SQLServer database. To make this user action service asynchronous, I have configured #EnableAsync in my main class.
#EnableAsync
public class WebApp extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
}
#Async
public void saveAction(ActionInfo event) {
actionDataService.save(event);
}
I want to ensure that whatever happens(Server crashes, database goes down etc), user action posted by the client through Rest API service must be saved in database (may be through retry when database comes online or Application server starts again).
Proposed Solutions
Followings are the solutions:
1) Write AsyncUncaughtExceptionHandler to handle exceptions that retries again to save user action. But if Server crashes, the user action objects shall be lost.
2) Use JMS queues to store user action. If Server crashes, the JMS queue should not be lost. It must be able to retry it when server restores. (Just an idea, does not have much knowledge about queues)
Can you please suggest?
I've been given an old WinForms app to update and improve. I am trying to add DI using SimpleInjector. I'm used to .Net MVC but this is my first time working with WinForms.
The application uses a lot of BackGround workers. My understanding is that this is specific to WinForms and each Background worker creates a new thread.
I think my problem is that when I want to save data to the DB using EF6 the SaveChanges method isn't able to save because of the multiple threads.
My SimpleInjector container is set up as follows
_container = new Container();
_container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
// Register DbContext
_container.Register<DbContext, MyDbContext>(Lifestyle.Scoped);
When I call SaveChanges on my dbContext I get a result of 0, which indicates that no records were saved to the database. In my debugger I get an error saying that the DbContext has been disposed. If this is happening before the save it explains why a 0 is returned from SaveChanges. Unfortunately the previous developer caught every exception so the application is trying to handle every error and this is making troubleshooting difficult and leading to unexpected behavior.
I am expecting a new DbContext to be created for each thread and that SaveChanges will save the changes made in each thread, so that what happens in one context won't affect other DbContexts in other threads.
When I am reading from the database I manually create a new DbContext in each method. Is it possible that when the using block has completed it is disposing the DbContext ?
using (var newDbContext = new MyDbContext())
{
return newDbContext.Set<TableA>().First(x => x.Id == id);
}
I'm hoping that if I have SimpleInjector configured correctly I won't need to do this either.
I'm a little lost at this stage and think I might not be understanding the documentation correctly, any advise would be greatly appreciated. Thanks in advance.
I am expecting a new DbContext to be created for each thread
This is not how TheadScopedLifestyle works. With the ThreadScopedLifestyle, there will be one instance of your registration within the context of an explicitly started Scope and this scope is thread-specific. This means that one thread can have many instances of that service, since a thread can live for a long time, while a Scope will typically only live for a short amount of time.
A typical use for ThreadScopedLifestyle is the following:
void MethodThatRunsInABackGroundThread()
{
using (ThreadScopedLifestyle.BeginScope(container))
{
var service = container.GetInstance<ISomeService>();
service.DoWork();
}
}
When you resolve Scoped instances (or some object graph that contains scoped instances) outside an active scope, Simple Injector will throw an exception.