Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run ElastAlert rule only once #1775

Open
adminnz opened this issue Jul 3, 2018 · 7 comments
Open

Run ElastAlert rule only once #1775

adminnz opened this issue Jul 3, 2018 · 7 comments

Comments

@adminnz
Copy link

adminnz commented Jul 3, 2018

I'm looking to run multiple ElastAlert instances each as Azure Functions with different rules triggered by external independent timers.
Is there a way to have ElastAlert run a specific action file just once and then exit? i.e. I dont want to utilize the run_every parameter and utilize my external timers to handle when ElastAlert performs the query against ElasticSearch.

@Qmando
Copy link
Member

Qmando commented Jul 3, 2018

If you provide --end, it will exit when it gets to that time. So doing something like elastalert --verbose --end $(date --iso-8601=seconds) will make elastalert run from the last end time up to the present time, then stop.

@adminnz
Copy link
Author

adminnz commented Jul 4, 2018

I have managed to install ElastAlert (pip install elastalert) into a python Azure Function.
Is it possible to run the ElastAlerter class without passing in config & action files and instead programatically set the values that the config/action files would of been parsed into?

@Qmando
Copy link
Member

Qmando commented Jul 6, 2018

Not really. It's technically possible of course, but very difficult.

Do you have access to making temp files?

@g-io
Copy link

g-io commented May 6, 2020

The solution proposed with the --end-flag seems not to be working anymore. If I get it right, the problem is that with the advent of elastalert 2.0 the job execution has been delegated to apscheduler's BackgroundScheduler. So in this case, the call to self.scheduler.start()is returning immediately and elastalert is exiting before the jobs have been run.

This is very unfortunate as this also breaks the 'run elastalert in Lambda-function' use-case.
Not sure how to run elastalert once now. Any clue would be much appreciated.

@Qmando
Copy link
Member

Qmando commented May 6, 2020

@g-io
I haven't tested this myself but the code looks like it supports this still.

           next_run = datetime.datetime.utcnow() + self.run_every
            # Quit after end_time has been reached
            if self.args.end:
                endtime = ts_to_dt(self.args.end)
                if next_run.replace(tzinfo=dateutil.tz.tzutc()) > endtime:
                    exit(0)

Perhaps it's exiting immediately for you because the --end flag is too close to the current time. Can you try making sure that it has at least one full run_every between the start and end times?
Maybe this is a timezone issue?

@g-io
Copy link

g-io commented May 7, 2020

@Qmando yes good point, that could work (although it needs to be at least run_every between now and end time it seems?), I've tested it yesterday already after looking into the code.

Even when an --end > now + run_everyis chosen however, the rules are not triggered in any case. I 1st thought they might have started and are just not finished, and execution is killed together with the elastalert exit. Luckily, the concurrent.futures pool that executes the jobs is sophisticated enough to wait for the end of rule execution on shutdown, it seems. Nice! 😄

However, I see 2 other problems now. 1st, the timing is more complicated. 2nd, I'm afraid to miss events with an --end in the future.

Re 1, basically there is

  • a startup time until the exit condition is evaluated. That might differ with every setup (rules to parse, network connectivity to ping elastic, ...). Let's say we estimate 5sec (generous for most cases).
  • a random, max 15s delay to dispatch rule jobs from scheduler to executor pool
  • a run_everydelay to dispatch internal jobs (alert, config-changes) to executor pool

Only if the jobs are already dispatched at exit, they will get executed. This means we come up with something like:

max(15s, run_every) < run_time - run_every

That must be fulfilled, with run_time to be minimized to save on lambda cost. Oh, and add the start overhead, say 5sec if you've come to a number.
In practice, I was running with run_every = 15s, --end= now + 35s.

Still feels bad and hacky 😞 -- There must be a better way to do it?

Re 2:
I've seen that, with no start time given (which is desirable in this setup), the next start time is taken from the end-time of the last run. Which is good, however not in this scenario, where end is in the future and elastalert will exit around end - run_every! I might miss hits that are between the real last execution time (at worst end - run_every) and end.

Not sure if my understanding is right here.

@briandefiant
Copy link

The solution proposed with the --end-flag seems not to be working anymore. If I get it right, the problem is that with the advent of elastalert 2.0 the job execution has been delegated to apscheduler's BackgroundScheduler. So in this case, the call to self.scheduler.start()is returning immediately and elastalert is exiting before the jobs have been run.

This is very unfortunate as this also breaks the 'run elastalert in Lambda-function' use-case. Not sure how to run elastalert once now. Any clue would be much appreciated.

I ran into this same issue. I ended up extending the ElastAlerter class and overriding the start() method to get it working. Details are here: jertel/elastalert2#1169

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants