hi juri,

i haven't done a full review, however, your approach via JobRunnableAdapter
looks fine.
with an optional lookup, you would even get rid of the default
implementation.
(+ imo it's a spi and not an api)

for different requirements (in >different< projects) we did all 3
approaches mentioned in this thread (and even some "hybrid" approaches e.g.
based on apache ignite).
that was one of the reasons for adding
SchedulerBaseConfig.JobCustomization.RUNNABLE_ADAPTER_CLASS_NAME.

quite soon i'll summarize and share an approach i (and several others) did
over and over the past few years.
in 2017 i suggested to add a simple abstraction for it (to ds), however,
maybe we can reach an agreement this time...

regards,
gerhard


Am Sa., 9. Feb. 2019 um 11:10 Uhr schrieb Juri Berlanda <
[email protected]>:

> Hi all,
>
> I created an issue at
> https://issues.apache.org/jira/browse/DELTASPIKE-1369. I already have a
> working prototype, though code polishing is still needed.
>
> @gerhard: I didn't know about the Listeners in Quartz, but I agree: what
> I propose is pretty much another way of doing
> TriggerListener.vetoJobExecution(Trigger trigger, JobExecutionContext
> context). But I guess (please correct me if I'm wrong) these Listeners
> cannot use Injection (except via BeanProvider, BeanManager and stuff
> like that). My approach - being a CDI Bean - would provide support for
> @Inject out of the box for any customizing bean.
>
> In addition, the Listeners seem to not provide a mechanism to prevent
> the scheduler from starting all together (see my initial use case in the
> first mail of this thread).
>
> I propose we move the discussion to the Jira issue. I also have listed
> some minor points I'd like your feedback on.
>
> Cheers,
>
> Juri
> ||||
>
> On 2/4/19 9:29 PM, Gerhard Petracek wrote:
> > hi @ all,
> >
> > limiting it to the scheduler-module is possible - but if it is the only
> > use-case, it wouldn't be needed, because it's easier to use
> > Scheduler#unwrap to register your own TriggerListener via
> > #getListenerManager. in the end such use-cases are the reason for
> > Scheduler#unwrap.
> >
> > regards,
> > gerhard
> >
> >
> >
> > Am Mo., 4. Feb. 2019 um 17:26 Uhr schrieb Mark Struberg
> > <[email protected]>:
> >
> >> 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