In my project based on Spring Boot 1.3.3, I integrated MyBatis with mybatis-spring-boot-starter 1.1.1 as persistence layer, all CRUD operation seems working fine separately, but the integration tests failed and I found the DB operation gets blocked in asynchronous task.
The test code looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = SapiApplication.class)
#Transactional
public class OrderIntegrationTest {
#Test
public void shouldUpdateOrder() throws InterruptedException{
Order order1 = getOrder1();
orderService.createOrder(order1);
Order order1updated = getOrder1Updated();
orderService.updateOrderAsync(order1updated);
Thread.sleep(1000l);
log.info("find the order!");
Order order1Db = orderService.findOrderById(order1.getOrderId());
log.info("found the order!");
assertEquals("closed", order1Db.getStatus());
}
}
The expected execution order is createOrder() -> updateOrderAsync() -> findOrderById(), but actually the execution order is createOrder() -> updateOrderAsync() started and blocked -> findOrderById() -> updateOrderAsync() continued and ended.
Log:
16:23:04.261 [executor1-1] INFO c.s.api.web.service.OrderServiceImpl - updating order: 2884384
16:23:05.255 [main] INFO c.s.a.w.service.OrderIntegrationTest - find the order!
16:23:05.280 [main] INFO c.s.a.w.service.OrderIntegrationTest - found the order!
16:23:05.299 [executor1-1] INFO c.s.api.web.service.OrderServiceImpl - updated order: 2884384
Other related code:
#Service
public class OrderServiceImpl implements OrderService {
#Autowired
private OrderDao orderDao;
#Async("executor1")
#Override
public void updateOrderAsync(Order order){
log.info("updating order: {}", order.getOrderId());
orderDao.updateOrder(order);
log.info("updated order: {}", order.getOrderId());
}
}
The DAO:
public interface OrderDao {
public int updateOrder(Order order);
public int createOrder(Order order);
public Order findOrderById(String orderId);
}
The Gradle dependencies:
dependencies {
compile 'org.springframework.boot:spring-boot-starter-jdbc'
compile 'org.springframework.boot:spring-boot-starter-security'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.mybatis.spring.boot:mybatis-spring-boot-starter:1.1.1'
compile 'ch.qos.logback:logback-classic:1.1.2'
compile 'org.springframework.boot:spring-boot-configuration-processor'
runtime 'mysql:mysql-connector-java'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile "org.springframework.security:spring-security-test"
}
The Spring configuration:
#SpringBootApplication
#EnableAsync
#EnableCaching
#EnableScheduling
#MapperScan("com.sapi.web.dao")
public class SapiApplication {
#Bean(name = "executor1")
protected Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(100);
return executor;
}
#Bean
#Primary
#ConfigurationProperties(prefix = "datasource.primary")
public DataSource numberMasterDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "secondary")
#ConfigurationProperties(prefix = "datasource.secondary")
public DataSource provisioningDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "jdbcTpl")
public JdbcTemplate jdbcTemplate(#Qualifier("secondary") DataSource dsItems) {
return new JdbcTemplate(dsItems);
}
public static void main(String[] args) {
SpringApplication.run(SapiApplication.class, args);
}
}
The properties:
mybatis.mapper-locations=classpath*:com/sapi/web/dao/*Mapper.xml
mybatis.type-aliases-package=com.sapi.web.vo
datasource.primary.driver-class-name=com.mysql.jdbc.Driver
datasource.primary.url=jdbc:mysql://10.0.6.202:3306/sapi
datasource.primary.username=xxx
datasource.primary.password=xxx
datasource.primary.maximum-pool-size=80
datasource.primary.max-idle=10
datasource.primary.max-active=150
datasource.primary.max-wait=10000
datasource.primary.min-idle=5
datasource.primary.initial-size=5
datasource.primary.validation-query=SELECT 1
datasource.primary.test-on-borrow=false
datasource.primary.test-while-idle=true
datasource.primary.time-between-eviction-runs-millis=18800
datasource.primary.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=100)
datasource.secondary.url = jdbc:mysql://10.0.6.202:3306/xdb
datasource.secondary.username = xxx
datasource.secondary.password = xxx
datasource.secondary.driver-class-name = com.mysql.jdbc.Driver
logging.level.org.springframework.web=DEBUG
The problem you see is caused by the fact that the whole test method shouldUpdateOrder is executed in one transaction. This means that any update operation that is executed in the thread that runs shouldUpdateOrder locks the record for the whole duration of the transaction (that is till exit from test method) and that record cannot be updated by another concurrent transaction (that is executed in async method).
To solve the issue you need to change transactions boundaries. In your case the correct way to emulate real life usage is to
create order in one transaction and finish the transaction
update order in another transaction
check that update is executed as expected in yet another transaction
Related
I have two application e.g) A, B
A has a Saga
B is just web application
A sent Command messages to B and
B sent exception for that Command to A's Saga and A's Saga received well
and B have a #ExceptionHandler which I hope to be invoked but it's not working
How can I make them be invoked?
EDIT
this is A application's Saga that sends command messages to B application
and deals with exception which B sent
#Saga
public class OrderSaga {
#Autowired
private transient CommandGateway commandGateway;
#StartSaga
#SagaEventHandler(associationProperty = "orderId")
public void handle(CreateOrderEvent evt) {
String paymentId = UUID.randomUUID().toString();
SagaLifecycle.associateWith("paymentId", paymentId);
commandGateway.send(new CreatedPaymentCommand(paymentId, evt.getUserId(),evt.getFoodPrice())).exceptionally(exp -> {
System.out.println("got it");
System.out.println(exp.getMessage());
return null;
});
}
}
this is B application that throws exception for test
#Aggregate
#NoArgsConstructor
public class PaymentAggregate {
#AggregateIdentifier
private String paymentId;
private String userId;
private PaymentStatus status;
#CommandHandler
public PaymentAggregate(CreatedPaymentCommand cmd) {
throw new IllegalStateException("this exception was came from payment aggregates");
// AggregateLifecycle.apply(new CreatedPaymentEvent(cmd.getPaymentId(),
// cmd.getUserId(),cmd.getMoney()));
}
#ExceptionHandler(resultType = IllegalStateException.class)
public void error(IllegalStateException exp) {
System.out.println(exp.getMessage());
}
// I want this #ExceptionHandler to be invoked
#EventSourcingHandler
public void on(CreatedPaymentEvent evt) {
this.paymentId = evt.getPaymentId();
this.userId = evt.getUserId();
}
}
A application catch exception well like below
2021-08-24 11:46:43.534 WARN 14244 --- [ault-executor-2] o.a.c.gateway.DefaultCommandGateway : Command 'com.common.cmd.CreatedPaymentCommand' resulted in org.axonframework.commandhandling.CommandExecutionException(this exception was came from payment aggregates)
got it
this exception was came from payment aggregates
but B is not I thought that B's #ExceptionHandler will catch that exception
in short, How can I make B's #ExceptionHandler to be invoked
It doesn't work right now because the exception is thrown from the constructor of your aggregate.
As you are using a constructor command handler, there is no instance present yet.
And without an instance, Axon Framework cannot spot the #ExceptionHandler annotated method you've set up.
This is the only missing point for the exception handlers at this stage. Honestly, the reference guide should be a bit more specific about this. I am sure this will change in the future, though.
There's a different approach for having a command handler that constructs the aggregate and that can use the #ExceptionHandler: with the #CreationPolicy annotation. The reference guide has this to say about it, by the way.
Thus, instead of having a constructor command handler, you would set up a regular command handler using the AggregateCreationPolicy.ALWAYS.
That would adjust your sample like so:
#Aggregate
#NoArgsConstructor
public class PaymentAggregate {
#AggregateIdentifier
private String paymentId;
private String userId;
private PaymentStatus status;
#CommandHandler
#CreationPolicy(AggregateCreationPolicy.ALWAYS)
public void handle(CreatedPaymentCommand cmd) {
throw new IllegalStateException("this exception was came from payment aggregates");
// AggregateLifecycle.apply(new CreatedPaymentEvent(cmd.getPaymentId(),
// cmd.getUserId(),cmd.getMoney()));
}
#ExceptionHandler(resultType = IllegalStateException.class)
public void error(IllegalStateException exp) {
System.out.println(exp.getMessage());
}
// I want this #ExceptionHandler to be invoked
#EventSourcingHandler
public void on(CreatedPaymentEvent evt) {
this.paymentId = evt.getPaymentId();
this.userId = evt.getUserId();
}
}
Please give this a try in your application, #YongD.
I could not find a definitive answer to whether it is safe to spawn threads within session-scoped JSF managed beans. The thread needs to call methods on the stateless EJB instance (that was dependency-injected to the managed bean).
The background is that we have a report that takes a long time to generate. This caused the HTTP request to time-out due to server settings we can't change. So the idea is to start a new thread and let it generate the report and to temporarily store it. In the meantime the JSF page shows a progress bar, polls the managed bean till the generation is complete and then makes a second request to download the stored report. This seems to work, but I would like to be sure what I'm doing is not a hack.
Check out EJB 3.1 #Asynchronous methods. This is exactly what they are for.
Small example that uses OpenEJB 4.0.0-SNAPSHOTs. Here we have a #Singleton bean with one method marked #Asynchronous. Every time that method is invoked by anyone, in this case your JSF managed bean, it will immediately return regardless of how long the method actually takes.
#Singleton
public class JobProcessor {
#Asynchronous
#Lock(READ)
#AccessTimeout(-1)
public Future<String> addJob(String jobName) {
// Pretend this job takes a while
doSomeHeavyLifting();
// Return our result
return new AsyncResult<String>(jobName);
}
private void doSomeHeavyLifting() {
try {
Thread.sleep(SECONDS.toMillis(10));
} catch (InterruptedException e) {
Thread.interrupted();
throw new IllegalStateException(e);
}
}
}
Here's a little testcase that invokes that #Asynchronous method several times in a row.
Each invocation returns a Future object that essentially starts out empty and will later have its value filled in by the container when the related method call actually completes.
import javax.ejb.embeddable.EJBContainer;
import javax.naming.Context;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class JobProcessorTest extends TestCase {
public void test() throws Exception {
final Context context = EJBContainer.createEJBContainer().getContext();
final JobProcessor processor = (JobProcessor) context.lookup("java:global/async-methods/JobProcessor");
final long start = System.nanoTime();
// Queue up a bunch of work
final Future<String> red = processor.addJob("red");
final Future<String> orange = processor.addJob("orange");
final Future<String> yellow = processor.addJob("yellow");
final Future<String> green = processor.addJob("green");
final Future<String> blue = processor.addJob("blue");
final Future<String> violet = processor.addJob("violet");
// Wait for the result -- 1 minute worth of work
assertEquals("blue", blue.get());
assertEquals("orange", orange.get());
assertEquals("green", green.get());
assertEquals("red", red.get());
assertEquals("yellow", yellow.get());
assertEquals("violet", violet.get());
// How long did it take?
final long total = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);
// Execution should be around 9 - 21 seconds
assertTrue("" + total, total > 9);
assertTrue("" + total, total < 21);
}
}
Example source code
Under the covers what makes this work is:
The JobProcessor the caller sees is not actually an instance of JobProcessor. Rather it's a subclass or proxy that has all the methods overridden. Methods that are supposed to be asynchronous are handled differently.
Calls to an asynchronous method simply result in a Runnable being created that wraps the method and parameters you gave. This runnable is given to an Executor which is simply a work queue attached to a thread pool.
After adding the work to the queue, the proxied version of the method returns an implementation of Future that is linked to the Runnable which is now waiting on the queue.
When the Runnable finally executes the method on the real JobProcessor instance, it will take the return value and set it into the Future making it available to the caller.
Important to note that the AsyncResult object the JobProcessor returns is not the same Future object the caller is holding. It would have been neat if the real JobProcessor could just return String and the caller's version of JobProcessor could return Future<String>, but we didn't see any way to do that without adding more complexity. So the AsyncResult is a simple wrapper object. The container will pull the String out, throw the AsyncResult away, then put the String in the real Future that the caller is holding.
To get progress along the way, simply pass a thread-safe object like AtomicInteger to the #Asynchronous method and have the bean code periodically update it with the percent complete.
Introduction
Spawning threads from within a session scoped managed bean is not necessarily a hack as long as it does the job you want. But spawning threads at its own needs to be done with extreme care. The code should not be written that way that a single user can for example spawn an unlimited amount of threads per session and/or that the threads continue running even after the session get destroyed. It would blow up your application sooner or later.
The code needs to be written that way that you can ensure that an user can for example never spawn more than one background thread per session and that the thread is guaranteed to get interrupted whenever the session get destroyed. For multiple tasks within a session you need to queue the tasks.
Also, all those threads should preferably be served by a common thread pool so that you can put a limit on the total amount of spawned threads at application level.
Managing threads is thus a very delicate task. That's why you'd better use the built-in facilities rather than homegrowing your own with new Thread() and friends. The average Java EE application server offers a container managed thread pool which you can utilize via among others EJB's #Asynchronous and #Schedule. To be container independent (read: Tomcat-friendly), you can also use the Java 1.5's Util Concurrent ExecutorService and ScheduledExecutorService for this.
Below examples assume Java EE 6+ with EJB.
Fire and forget a task on form submit
#Named
#RequestScoped // Or #ViewScoped
public class Bean {
#EJB
private SomeService someService;
public void submit() {
someService.asyncTask();
// ... (this code will immediately continue without waiting)
}
}
#Stateless
public class SomeService {
#Asynchronous
public void asyncTask() {
// ...
}
}
Asynchronously fetch the model on page load
#Named
#RequestScoped // Or #ViewScoped
public class Bean {
private Future<List<Entity>> asyncEntities;
#EJB
private EntityService entityService;
#PostConstruct
public void init() {
asyncEntities = entityService.asyncList();
// ... (this code will immediately continue without waiting)
}
public List<Entity> getEntities() {
try {
return asyncEntities.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new FacesException(e);
} catch (ExecutionException e) {
throw new FacesException(e);
}
}
}
#Stateless
public class EntityService {
#PersistenceContext
private EntityManager entityManager;
#Asynchronous
public Future<List<Entity>> asyncList() {
List<Entity> entities = entityManager
.createQuery("SELECT e FROM Entity e", Entity.class)
.getResultList();
return new AsyncResult<>(entities);
}
}
In case you're using JSF utility library OmniFaces, this could be done even faster if you annotate the managed bean with #Eager.
Schedule background jobs on application start
#Singleton
public class BackgroundJobManager {
#Schedule(hour="0", minute="0", second="0", persistent=false)
public void someDailyJob() {
// ... (runs every start of day)
}
#Schedule(hour="*/1", minute="0", second="0", persistent=false)
public void someHourlyJob() {
// ... (runs every hour of day)
}
#Schedule(hour="*", minute="*/15", second="0", persistent=false)
public void someQuarterlyJob() {
// ... (runs every 15th minute of hour)
}
#Schedule(hour="*", minute="*", second="*/30", persistent=false)
public void someHalfminutelyJob() {
// ... (runs every 30th second of minute)
}
}
Continuously update application wide model in background
#Named
#RequestScoped // Or #ViewScoped
public class Bean {
#EJB
private SomeTop100Manager someTop100Manager;
public List<Some> getSomeTop100() {
return someTop100Manager.list();
}
}
#Singleton
#ConcurrencyManagement(BEAN)
public class SomeTop100Manager {
#PersistenceContext
private EntityManager entityManager;
private List<Some> top100;
#PostConstruct
#Schedule(hour="*", minute="*/1", second="0", persistent=false)
public void load() {
top100 = entityManager
.createNamedQuery("Some.top100", Some.class)
.getResultList();
}
public List<Some> list() {
return top100;
}
}
See also:
Spawning threads in a JSF managed bean for scheduled tasks using a timer
I tried this and works great from my JSF managed bean
ExecutorService executor = Executors.newFixedThreadPool(1);
#EJB
private IMaterialSvc materialSvc;
private void updateMaterial(Material material, String status, Location position) {
executor.execute(new Runnable() {
public void run() {
synchronized (position) {
// TODO update material in audit? do we need materials in audit?
int index = position.getMaterials().indexOf(material);
Material m = materialSvc.getById(material.getId());
m.setStatus(status);
m = materialSvc.update(m);
if (index != -1) {
position.getMaterials().set(index, m);
}
}
}
});
}
#PreDestroy
public void destory() {
executor.shutdown();
}
I am using spring-kafka 2.2.8 and trying to understand if there is an option to deploy a kafka consumer being in pause mode until i signal to start consume the messages. Please suggest.
I see in the below post, we can pause and start the consumer but I need the consumer to be in pause mode when it's deployed.
how to pause and resume #KafkaListener using spring-kafka
#KafkaListener(id = "foo", ..., autoStartup = "false")
Then start it using the KafkaListenerEndpointRegistry when you are ready
registry.getListenerContainer("foo").start();
There is not much point in starting it in paused mode, but you can do that...
#SpringBootApplication
public class So62329274Application {
public static void main(String[] args) {
SpringApplication.run(So62329274Application.class, args);
}
#KafkaListener(id = "so62329274", topics = "so62329274", autoStartup = "false")
public void listen(String in) {
System.out.println(in);
}
#Bean
public NewTopic topic() {
return TopicBuilder.name("so62329274").partitions(1).replicas(1).build();
}
#Bean
public ApplicationRunner runner(KafkaListenerEndpointRegistry registry, KafkaTemplate<String, String> template) {
return args -> {
template.send("so62329274", "foo");
registry.getListenerContainer("so62329274").pause();
registry.getListenerContainer("so62329274").start();
System.in.read();
registry.getListenerContainer("so62329274").resume();
};
}
}
You will see a log message like this when the partitions are assigned:
Paused consumer resumed by Kafka due to rebalance; consumer paused again, so the initial poll() will never return any records
Currently I'm beginnging with Spring + reactive programming. My aim is to return a result in a REST-endpoint from a long running method (polling on a database). I'm stuck on the api. I simply don't know how to return the result as Mono in my FooService.findFoo method.
#RestController
public class FooController {
#Autowired
private FooService fooService;
#GetMapping("/foo/{id}")
private Mono<ResponseEntity<Foo> findById(#PathVariable String id) {
return fooService.findFoo(id).map(foo -> ResponseEntity.ok(foo)) //
.defaultIfEmpty(ResponseEntity.notFound().build())
}
...
}
#Service
public class FooService {
public Mono<Foo> findFoo(String id) {
// this is the part where I'm stuck
// I want to return the results of the pollOnDatabase-method
}
private Foo pollOnDatabase(String id) {
// polling on database for a while
}
}
Use the Mono.fromSupplier method! :)
#Service
public class FooService {
public Mono<Foo> findFoo(String id) {
return Mono
.fromSupplier(() -> pollOnDatabase(id))
.subscribeOn(Schedulers.boundedElastic());
}
private Foo pollOnDatabase(String id) {
// polling on database for a while
}
}
With this method we return a Mono value ASAP, constant time with a supplier which will be evaluated on demand by the caller's subscribe. This is the non blocking way to call a long-running-blocking method.
BE AWARE that without subscription on boundedElastic the blocking pollOnDatabase method will block the original thread, which leads to thread starvation. You can find different schedules for every kind of tasks here.
DO NOT use Mono.just with long-running calculations as it will run the calculation before returning the Mono instance, thereby blocking the given thread.
+1: Watch this video to learn to avoid "reactor meltdown". Use some lib to detect blocking calls from non-blocking threads.
It's pretty simple. You could just do
#Service
public class FooService {
public Mono<Foo> findFoo(String id) {
return Mono.just(pollOnDatabase(id));
}
private Foo pollOnDatabase(String id) {
// polling on database for a while
}
}
I am actually working in an ASP.Net MVC 4 web application where we are using NInject for dependency injection. We are also using UnitOfWork and Repositories based on Entity framework.
We would like to use Quartz.net in our application to start some custom job periodically. I would like that NInject bind automatically the services that we need in our job.
It could be something like this:
public class DispatchingJob : IJob
{
private readonly IDispatchingManagementService _dispatchingManagementService;
public DispatchingJob(IDispatchingManagementService dispatchingManagementService )
{
_dispatchingManagementService = dispatchingManagementService ;
}
public void Execute(IJobExecutionContext context)
{
LogManager.Instance.Info(string.Format("Dispatching job started at: {0}", DateTime.Now));
_dispatchingManagementService.DispatchAtomicChecks();
LogManager.Instance.Info(string.Format("Dispatching job ended at: {0}", DateTime.Now));
}
}
So far, in our NInjectWebCommon binding is configured like this (using request scope):
kernel.Bind<IDispatchingManagementService>().To<DispatchingManagementService>();
Is it possible to inject the correct implementation into our custom job using NInject ? and how to do it ? I have read already few posts on stack overflow, however i need some advises and some example using NInject.
Use a JobFactory in your Quartz schedule, and resolve your job instance there.
So, in your NInject config set up the job (I'm guessing at the correct NInject syntax here)
// Assuming you only have one IJob
kernel.Bind<IJob>().To<DispatchingJob>();
Then, create a JobFactory: [edit: this is a modified version of #BatteryBackupUnit's answer here]
public class NInjectJobFactory : IJobFactory
{
private readonly IResolutionRoot resolutionRoot;
public NinjectJobFactory(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
// If you have multiple jobs, specify the name as
// bundle.JobDetail.JobType.Name, or pass the type, whatever
// NInject wants..
return (IJob)this.resolutionRoot.Get<IJob>();
}
public void ReturnJob(IJob job)
{
this.resolutionRoot.Release(job);
}
}
Then, when you create the scheduler, assign the JobFactory to it:
private IScheduler GetSchedule(IResolutionRoot root)
{
var schedule = new StdSchedulerFactory().GetScheduler();
schedule.JobFactory = new NInjectJobFactory(root);
return schedule;
}
Quartz will then use the JobFactory to create the job, and NInject will resolve the dependencies for you.
Regarding scoping of the IUnitOfWork, as per a comment of the answer i linked, you can do
// default for web requests
Bind<IUnitOfWork>().To<UnitOfWork>()
.InRequestScope();
// fall back to `InCallScope()` when there's no web request.
Bind<IUnitOfWork>().To<UnitOfWork>()
.When(x => HttpContext.Current == null)
.InCallScope();
There's only one caveat that you should be aware of:
With incorrect usage of async in a web request, you may mistakenly be resolving a IUnitOfWork in a worker thread where HttpContext.Current is null. Now without the fallback binding, this would fail with an exception which would show you that you've done something wrong. With the fallback binding however, the issue may present itself in an obscured way. That is, it may work sometimes, but sometimes not. This is because there will be two (or even more) IUnitOfWork instances for the same request.
To remedy this, we can make the binding more specific. For this, we need some parameter to tell us to use another than InRequestScope(). Have a look at:
public class NonRequestScopedParameter : Ninject.Parameters.IParameter
{
public bool Equals(IParameter other)
{
if (other == null)
{
return false;
}
return other is NonRequestScopedParameter;
}
public object GetValue(IContext context, ITarget target)
{
throw new NotSupportedException("this parameter does not provide a value");
}
public string Name
{
get { return typeof(NonRequestScopedParameter).Name; }
}
// this is very important
public bool ShouldInherit
{
get { return true; }
}
}
now adapt the job factory as follows:
public class NInjectJobFactory : IJobFactory
{
private readonly IResolutionRoot resolutionRoot;
public NinjectJobFactory(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return (IJob) this.resolutionRoot.Get(
bundle.JobDetail.JobType,
new NonrequestScopedParameter()); // parameter goes here
}
public void ReturnJob(IJob job)
{
this.resolutionRoot.Release(job);
}
}
and adapt the IUnitOfWork bindings:
Bind<IUnitOfWork>().To<UnitOfWork>()
.InRequestScope();
Bind<IUnitOfWork>().To<UnitOfWork>()
.When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any())
.InCallScope();
This way, if you use async wrong, there'll still be an exception, but IUnitOfWork scoping will still work for quartz tasks.
For any users that could be interested, here is the solution that finally worked for me.
I have made it working doing some adjustment to match my project. Please note that in the method NewJob, I have replaced the call to Kernel.Get by _resolutionRoot.Get.
As you can find here:
public class JobFactory : IJobFactory
{
private readonly IResolutionRoot _resolutionRoot;
public JobFactory(IResolutionRoot resolutionRoot)
{
this._resolutionRoot = resolutionRoot;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
return (IJob)_resolutionRoot.Get(
bundle.JobDetail.JobType, new NonRequestScopedParameter()); // parameter goes here
}
catch (Exception ex)
{
LogManager.Instance.Info(string.Format("Exception raised in JobFactory"));
}
}
public void ReturnJob(IJob job)
{
}
}
And here is the call schedule my job:
public static void RegisterScheduler(IKernel kernel)
{
try
{
var scheduler = new StdSchedulerFactory().GetScheduler();
scheduler.JobFactory = new JobFactory(kernel);
....
}
}
Thank you very much for your help
Thanks so much for your response. I have implemented something like that and the binding is working :):
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var resolver = DependencyResolver.Current;
var myJob = (IJob)resolver.GetService(typeof(IJob));
return myJob;
}
As I told before I am using in my project a service and unit of work (based on EF) that are both injected with NInject.
public class DispatchingManagementService : IDispatchingManagementService
{
private readonly IUnitOfWork _unitOfWork;
public DispatchingManagementService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
}
Please find here how I am binding the implementations:
kernel.Bind<IUnitOfWork>().To<EfUnitOfWork>()
kernel.Bind<IDispatchingManagementService>().To<DispatchingManagementService>();
kernel.Bind<IJob>().To<DispatchingJob>();
To resume, the binding of IUnitOfWork is done for:
- Eevery time a new request is coming to my application ASP.Net MVC: Request scope
- Every time I am running the job: InCallScope
What are the best practices according to the behavior of EF ? I have find information to use CallInScope. Is it possible to tell NInject to get a scope ByRequest everytime a new request is coming to the application, and a InCallScope everytime my job is running ? How to do that ?
Thank you very much for your help