doesn't sound wrong - actually sounds really fine ;)

Do you probably want to provide a ticket and patch?

LieGrue,
strub

> Am 04.02.2019 um 14:19 schrieb Juri Berlanda <[email protected]>:
> 
> Hi,
> 
> I still think it would be nice to just have a simple mechanism telling "Just 
> don't start here".
> 
> I'm sceptic on a.) and b.) because they would introduce a database binding to 
> DeltaSpike, which I think may make it hard to use in some stacks (think 
> projects running on NoSQL databases). In addition, I think something similar 
> as you proposed in a.) can already be achieved by running Quartz in 
> ClusteredMode, though I never tried that.
> 
> What I would propose is some pluggable Bean (via Alternative, Specializes or 
> stuff like that) with 2 functions:
> 
> boolean isSchedulerEnabled();
> 
> boolean shouldJobBeStarted(Class<T>);
> 
> The default implementation would return true on both. Any Alternative could 
> then return false on isSchedulerEnabled() to fully disable it (lowering 
> overall overhead in a scenario as mine), or do something smart in 
> shouldJobBeStarted() to determine at Runtime whether a specific Job should be 
> ran on the current node (should accomodate for your usecase).
> 
> What do you think?
> 
> Cheers,
> 
> Juri
> 
> On 1/30/19 9:13 AM, Mark Struberg wrote:
>> Hi folks!
>> 
>> Yes, that solution works.
>> 
>> I had the same problem (multiple nodes, code should only run once).
>> Pinning to one cluster node is a possible solution, but if that one node is 
>> down then the processing stops.
>> I went for another solution. I wrote some Interceptor which basically guards 
>> against a central DB.
>> 
>> There are 2 different strategies:
>> a.) Keep an pesimistic lock on a row in a DB. One row per Class or locking 
>> key. (DB must support row locking).
>>  Pro: easy to implement. Most work is done by the database
>>  Con: If the whole thread gets stuck then you're in back luck. One is also 
>> bound to the maximum transaction timeout.
>>   So if you want to have a task running for one hour (doing e.g. multiple 
>> transaction batches) you cannot use this strategy.
>> 
>> b.) Have a 'watchdog' table which remembers the node and whether active. 2 
>> Minutes not updated means that the task blew up and another node might take 
>> up.
>>  Pro: sufficiently easy to implement. A background thread which is a 
>> watchdog and uipdates the 'lastActive' timestamp in the DB in the background.
>>  Con: It takes a while for another node to pick up the work. Minimum 2 
>> minutes. We also need a clear 'nodeId'. That might be the IP, but if 
>> multiple JVMs run on the same box then you need some custom identifier. The 
>> JVM id would be a candidate as it is unique. Otoh a restart would mean 2 
>> minutes pause.
>> 
>> c.) no database at all but network based locking. Might be easier or harder 
>> to setup depending on your infrastructure and security measures.
>> 
>> Should we implement any of these in DeltaSpike?
>> Which one makes more sense?
>> (I personally went for option b for my use cases)
>> 
>> LieGrue,
>> strub
>> 
>> 
>>> Am 28.01.2019 um 13:28 schrieb Juri Berlanda <[email protected]>:
>>> 
>>> Hi,
>>> 
>>> just for completeness sake: I was able to achieve what I wanted using a 
>>> custom config source. I presume this is not how it is supposed to be, but 
>>> it works:
>>> 
>>> public class SchedulerConfigSource implements ConfigSource {
>>>     private static final String CLASS_DEACTIVATOR_KEY = 
>>> "org.apache.deltaspike.core.spi.activation.ClassDeactivator";
>>>     private static final String CLASS_DEACTIVATOR_VALUE = 
>>> "org.apache.deltaspike.core.impl.activation.DefaultClassDeactivator";
>>>     private static final String SCHEDULER_DISABLED_KEY = 
>>> "deactivate.org.apache.deltaspike.scheduler.impl.SchedulerExtension";
>>> 
>>>     private final int ordinal;
>>> 
>>>     SchedulerConfigSource(int ordinal) {
>>>         this.ordinal = ordinal;
>>>     }
>>> 
>>>     @Override
>>>     public int getOrdinal() {
>>>         return ordinal;
>>>     }
>>> 
>>>     @Override
>>>     public Map<String, String> getProperties() {
>>>         return Stream.of(CLASS_DEACTIVATOR_KEY, SCHEDULER_DISABLED_KEY)
>>>                 .collect(Collectors.toMap(Function.identity(), 
>>> this::getPropertyValue));
>>>     }
>>> 
>>>     @Override
>>>     public String getPropertyValue(String key) {
>>>         if (CLASS_DEACTIVATOR_KEY.equals(key))
>>>             return CLASS_DEACTIVATOR_VALUE;
>>>         if (SCHEDULER_DISABLED_KEY.equals(key))
>>>             return Boolean.toString(!isSchedulerNode());
>>>         return null;
>>>     }
>>> 
>>>     private boolean isSchedulerNode() {
>>>         // Evaluate the condition here
>>>     }
>>> 
>>>     @Override
>>>     public String getConfigName() {
>>>         return "SchedulerConfigSource";
>>>     }
>>> 
>>>     @Override
>>>     public boolean isScannable() {
>>>         return false;
>>>     }
>>> }
>>> 
>>> Thought I may as well add it if somebody else. And don't forget to register 
>>> the ConfigSource.
>>> 
>>> I presume there is a better way to achieve this. If you know of one, please 
>>> let me know.
>>> 
>>> Cheers,
>>> 
>>> Juri
>>> 
>>> On 1/25/19 3:56 PM, Juri Berlanda wrote:
>>>> I was able to achieve similar with Deltaspike's own Deactivable. It does 
>>>> work, i.e. I can set:
>>>> 
>>>> org.apache.deltaspike.core.spi.activation.ClassDeactivator=org.apache.deltaspike.core.impl.activation.DefaultClassDeactivator
>>>> deactivate.org.apache.deltaspike.scheduler.impl.SchedulerExtension=true
>>>> 
>>>> in my configs, and Scheduler stays off. But - as mentioned - I need this 
>>>> to be evaluated on system startup, not at Config level. So I tried 
>>>> implementing my own SchedulerExtension like:
>>>> 
>>>> public class MySchedulerExtension extends SchedulerExtension {
>>>>     @Override
>>>>     protected void init(@Observes BeforeBeanDiscovery beforeBeanDiscovery) 
>>>> {
>>>>         if (isSchedulerNode())
>>>>             super.init(beforeBeanDiscovery);
>>>>     }
>>>> }
>>>> 
>>>> I can register it via SPI and from the logs I see it is indeed 
>>>> initialized, while SchedulerExtension is not. Victory, right? Not quite...
>>>> 
>>>> I am testing this with OpenWebbeans 2.0.6., and I face the problem, that 
>>>> CDI now complains about ambiguous Bean for SchedulerExtension in 
>>>> SchedulerProducer (which I can see where that comes from), but I am just 
>>>> not able to exclude SchedulerProducer - I wouldn't even need it. I tried 
>>>> various combinations of @Specialize, @Alternative and <scan><exclude 
>>>> .../></scan>, but none of them seem to work. I guess the reason for it is 
>>>> the CDI 1.0 beans.xml in scheduler-impl? Can anybody confirm? Would it be 
>>>> possible to move higher - 1.1 at least for getting support for 
>>>> <scan><exclude .../></scan>?
>>>> 
>>>> This leads me to the assumption, that scheduler-impl's SchedulerExtension 
>>>> is just not extensible at the moment. Or did anybody succeed in such an 
>>>> endeavor?
>>>> 
>>>> Since I do not want to patch the implementation, my next guess is to 
>>>> implement a custom ConfigSource, which evaluates isSchedulerNode() and 
>>>> sets deactivate.org.apache.deltaspike.scheduler.impl.SchedulerExtension 
>>>> accordingly. Does that make sense?
>>>> 
>>>> Kind regards,
>>>> 
>>>> Juri
>>>> 
>>>> On 1/24/19 9:04 PM, Alex Roytman wrote:
>>>>> in my case i need to be able to turn it on/off on demand and I only have
>>>>> couple of daily tasks so for me it was good enough
>>>>> If if you just need to do it on startup by node type you could bind it to 
>>>>> a
>>>>> property
>>>>> @Scheduled(cronExpression = "{reindex.schedule}")
>>>>> public class ReindexTask implements org.quartz.Job {
>>>>> ...
>>>>> and that property could probably be a cron expression which never fire on
>>>>> all of your nodes but the scheduler
>>>>> not nice but the whole thing is rather static - admittedly i did not dig
>>>>> very deep
>>>>> 
>>>>> 
>>>>> On Thu, Jan 24, 2019 at 2:44 PM Juri Berlanda <[email protected]>
>>>>> wrote:
>>>>> 
>>>>>> Thanks for the quick reply. I thought about that, but I don't like this
>>>>>> solution, since it involves to much boilerplate for my taste. In
>>>>>> addition, I find it cumbersome having to add these 2 lines in every
>>>>>> single task. I also thought about having an abstract base class for this
>>>>>> purpose, but I'm not happy with the solution...
>>>>>> 
>>>>>> In short: I hoped for a cleaner solution.
>>>>>> 
>>>>>> On 1/24/19 7:03 PM, Alex Roytman wrote:
>>>>>>> Let the scheduler run and execute your task  but inside of the task
>>>>>> itself
>>>>>>> check if you want to execute your logic or short circuit it to noop.
>>>>>> Since
>>>>>>> you do not run it often should not be an overhead and it will let you
>>>>>> fail
>>>>>>> over for any mode to execute it as long as you have a mechanism to lock
>>>>>> on
>>>>>>> something and record execution result to avoid simultaneous execution or
>>>>>>> double exexution
>>>>>>> 
>>>>>>> On Thu, Jan 24, 2019, 12:37 PM Juri Berlanda <[email protected]
>>>>>>> wrote:
>>>>>>> 
>>>>>>>> Hi,
>>>>>>>> 
>>>>>>>> I am currently trying to implement scheduled jobs using DeltaSpike's
>>>>>>>> Scheduler module, and I really like how little boilerplate I need for
>>>>>>>> getting it up and running.
>>>>>>>> 
>>>>>>>> Our application runs on multiple nodes, but the tasks are very
>>>>>>>> inexpensive, run only once a day, and I don't need failover - if they
>>>>>>>> fail once, and succeed the day after its totally fine. Therefore I'd
>>>>>>>> like to avoid setting up Quartz in clustered mode. But I still want the
>>>>>>>> Jobs to only run once. So my idea was to restrict the execution of the
>>>>>>>> jobs to a single scheduler node.
>>>>>>>> 
>>>>>>>> So my question is: Is it possible to somehow hook into the Scheduler
>>>>>>>> module to say something like:
>>>>>>>> 
>>>>>>>> if (isSchedulerNode())
>>>>>>>>      startScheduler();
>>>>>>>> else
>>>>>>>>      doNothing();
>>>>>>>> 
>>>>>>>> It would be perfect if said isSchedulerNode() could be evaluated on
>>>>>>>> system startup (e.g. acquire a distributed lock) and would not rely on
>>>>>>>> static values (e.g. config files, environment variables, etc.).
>>>>>>>> 
>>>>>>>> I can see how this is a bad idea in general (no load-balancing, no
>>>>>>>> failover) and I do have some ideas on how I would implement that. But
>>>>>>>> for these jobs I just don't care about any of this, so I'd like to 
>>>>>>>> avoid
>>>>>>>> having to set up a whole lot of infrastructure around my application
>>>>>>>> just to see this working.
>>>>>>>> 
>>>>>>>> Is there a possibility to achieve this without patching
>>>>>>>> deltaspike-scheduler-module-impl?
>>>>>>>> 
>>>>>>>> Kind regards,
>>>>>>>> 
>>>>>>>> Juri
>>>>>>>> 
>>>>>>>> 

Reply via email to