0

I have a custom ThreadPoolTaskScheduler which I want to use in LockableTaskScheduler instance I defined in the config as below:

@Configuration
public class ApplicationConfiguration {

    @Autowired DataSource dataSource;

    @Bean
    public LockProvider lockProvider() {
        return new JdbcTemplateLockProvider(
                JdbcTemplateLockProvider.Configuration.builder()
                        .withJdbcTemplate(new JdbcTemplate(dataSource))
                        .usingDbTime()
                        .build()
        );
    }

    @Bean
    public TaskScheduler lockableTaskScheduler(){
           ThreadPoolTaskScheduler threadPoolTaskScheduler = new 
           ThreadPoolTaskScheduler();
           threadPoolTaskScheduler.setPoolSize(2);
           threadPoolTaskScheduler.initialize();
           return new LockableTaskScheduler(threadPoolTaskScheduler, lockManager());
    }

    @Bean
    public LockManager lockManager(){
        return new DefaultLockManager(lockProvider(), lockConfigurationExtractor());
    }

    @Bean /*** PROBLEM HERE ***/
    public LockConfigurationExtractor lockConfigurationExtractor(){
        return new SpringLockConfigurationExtractor();
    }
}

And I instantiate dynamic schedules programatically as below:

@Autowired
TaskScheduler lockableTaskScheduler;
...    
CronTrigger cronTrigger = new CronTrigger(cronExpression, TimeZone.getTimeZone(TimeZone.getDefault().getID()));
    Runnable runnable = () -> someMethod();
    ScheduledFuture<?> scheduledTask = lockableTaskScheduler.schedule(runnable, cronTrigger);

But I couldn't find any public implementation of LockConfigurationExtractor to create a LockConfigurationExtractor bean.

P.S. I went through the source code and the test cases. But LockConfigurationExtractor does not seem to have a public concrete implementation accessible outside the library package.

Is there any other way to define/get the DefaultLockManager bean?


Edit:

Actually my main goal is not to create the LockableTaskScheduler at all. I just want to schedule a "Lockable" runnable somehow as:

ScheduledFuture<?> scheduledTask = lockableTaskScheduler.schedule(<lockable_runnable>, cronTrigger);

So that when the runnable is fired it can not run simultaneously in another node. (note: The dynamic/programmatic scheduling part of the business logic is not avoidable ATM)

Bere
  • 1,627
  • 2
  • 16
  • 22
  • Can you please describe what are you trying achieve, what is the purpose of the configuration? I am afraid that SpringLockConfigurationExtractor would not be able to extract configuration from you runnable, so it does not matter if you can not instantiate it. – Lukas Jan 14 '21 at 07:53
  • @Lukas I edited my question to add few details. Please take a look. Thanks! – Bere Jan 14 '21 at 15:09

3 Answers3

3

I have found a workaround for it. I cascaded two runnables and pass the second to the TaskScheduler schedule(...) method. Roughly it looks like this:

        Runnable runnable1 = () -> someMethod();

        Runnable runnable2 = () -> { 
            LockingTaskExecutor executor = new DefaultLockingTaskExecutor(lockProvider);
            Instant lockAtMostUntil = Instant.now().plusSeconds(600);
            executor.executeWithLock(runnable1, new LockConfiguration(<lock_name>, lockAtMostUntil));
        };
 
        CronTrigger cronTrigger = new CronTrigger(<cron-expression>, TimeZone.getTimeZone(TimeZone.getDefault().getID()));    
        ScheduledFuture<?> scheduledTask = scheduler.schedule(runnable2, cronTrigger);
Bere
  • 1,627
  • 2
  • 16
  • 22
1

You can use LockableTaskScheduler but you have to implement your own LockConfigurationExtractor - the generic one will not be able to extract lock configuration from your runnable. One possible implementation is to extend Runnable with a method that returns LockConfiguration. The LockConfigurationExtractor will just get it from the runnable.

Lukas
  • 13,606
  • 9
  • 31
  • 40
0

Both approaches worked for me, so you can create another Runnable just like @Bere did pass the other Runnable or you do a bean like Lukas said and pass in the LockConfiguration to your Runnable

@Data
@AllArgsConstructor
@Slf4j
public class YourRunnable implements Runnable {

  private String name;

  private LockConfiguration lockConfiguration;

  @Override
  public void run() {
    log.info("Starting task with name: {}", name);
  }
} 

 

    @Bean
      public LockConfigurationExtractor lockConfigurationExtractor(){
        return new LockConfigurationExtractor() {
          @Override
          public Optional<LockConfiguration> getLockConfiguration(Runnable task) {
            if (task instanceof YourRunnable) {
              return Optional.of(((YourRunnable) task).getLockConfiguration());
            }
            return Optional.empty();
          }
        };
      }