How did I get here? I'm not good with computers.
ahawker / crython Goto Github PK
View Code? Open in Web Editor NEWLightweight task scheduler using cron expressions
License: Other
Lightweight task scheduler using cron expressions
License: Other
when you trying to new a tab like this:
Tab=crython.tab.CronTab(name='test',logger=logging.getLogger('xxx'))
it throws a Exception.
it is because you try to call the super function ,and thread.init() does't accept the keyword logger.
so you should pop the 'logger' keyword out ,the call super function
There is some mismatch in weekday...
I am trying to run something on friday. But debug log shows it is not matching on a friday.
import crython
from datetime import datetime
import logging
logging.basicConfig(level=logging.DEBUG)
@crython.job(expr="*/25 * 9-16 * * fri *")
def test():
print("im at %s",datetime.now())
crython.start()
#crython.stop()
#crython.join(timeout=5)
On Friday, logs:
DEBUG:crython.crython.expression:Field "weekday:4" does not match value "5"
The expression @reboot
does not work. Running crython.start()
outputs this error:
Traceback (most recent call last):
[...
File "/home/joost/Ontwikkeling/GoAbout/Docker/tarsnap/crython/local/lib/python2.7/site-packages/crython/job.py", line 39, in decorator
wrapper.cron_expression = expression.CronExpression.new(expr, **fields)
File "/home/joost/Ontwikkeling/GoAbout/Docker/tarsnap/crython/local/lib/python2.7/site-packages/crython/expression.py", line 116, in new
return cls.from_str(expression) if expression else cls.from_kwargs(**kwargs)
File "/home/joost/Ontwikkeling/GoAbout/Docker/tarsnap/crython/local/lib/python2.7/site-packages/crython/expression.py", line 127, in from_str
fields = _expression_str_to_dict(expression, reboot_sentinel=reboot_sentinel)
File "/home/joost/Ontwikkeling/GoAbout/Docker/tarsnap/crython/local/lib/python2.7/site-packages/crython/expression.py", line 69, in _expression_str_to_dict
raise ValueError('Expression contains {0} fields; expects {1}'.format(len(values), expression_field_count))
ValueError: Expression contains 1 fields; expects 7
The cause is probably the line if expression is REBOOT_KEYWORD
in expression.py
which should be if expression == REBOOT_KEYWORD
.
the function 'matches' in expression.py always return true.
the problem is on line 195:
yield (name,match)
because yield return a tuple,so the all() method will always return True(forgive my pool English,I know why it performed like that,but I don't know how to say that).
to fix it ,just change like this
yield match
on line 195,expression.py
That version is horribly broken and never should have been published.
Add support for Python 3.X versions where "X" is still TBD (likely 3.2+).
Options:
six
Not an issue, but a question. Great work btw!
How do I update job with new cron expression.
I tried
crontab.start()
time.sleep(5)
update job expr with 'some new expr'
crontab.stop()
crontab.start()
time.sleep(5)
Not working
Log:
Traceback (most recent call last):
File "test-0.py", line 27, in
crython.start()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/crython/tab.py", line 129, in start
default_tab.start()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 842, in start
raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once
First of all this module is just what I wanted (Supporting second-wide functionality)!!! Thanks for the author!
My problem is I have all config of tasks in DB and want to run all tasks one-by-one.
My code:
map_from_db = {
'*/1 * * * * * *': 'every 1 sec',
'*/2 * * * * * *': 'every 2 sec',
}
for ex, speech in map_from_db.items():
@crython.job(expr=ex)
def func():
print(speech)
crython.start()
It seems crython is only selecting random one task and start running.
What should I do?
Checking in again!
when running:
@crython.job(hour=range(6,24,1))
I expected a trigger to happen every second, of every minute, og every hour between 6 and 24, however it seems as if the range have to start at 0 and end at 24, to fit the hour range.
However, when giving hour a list:
@crython.job(hour=[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23])
I get the expected behavior. Maybe I am just missing something python-related. I just stumbled upon either an undocumented feature, using lists, or a bug when using range. You decide ;)
You should probably add the six
dependency to setup.py
.
Documentation in README mismatch for weekly cronjob expression.
# Fire once a week.
@crython.job(expr='0 0 0 * * 0 *')
def foo():
print "Back in line, maggot! - Kearny"
and
@Weekly | Run once a week at midnight in the morning of Sunday | 0 0 0 0 * 0 *
Looking in details of the expression in the code for @weekly
keyword, we can see the actual expression used:
Line 34 in 12d9ca9
As shown in below section, the expression is not correct.
According to the crython docstring, this is how an expression is constructed:
Represents an entire cron expression.
An expression consists of seven, space delimited fields that represent the following values::
+------------- second (0 - 59)
| +------------- minute (0 - 59)
| | +------------- hour (0 - 23)
| | | +------------- day (1 - 31)
| | | | +------------- month (1 - 12)
| | | | | +------------- weekday (0 - 6) (Sunday to Saturday; 7 is also Sunday)
| | | | | | +------------- year (1970 - 2099)
| | | | | | |
| | | | | | |
* * * * * * *
I believe all keywords using incorrectly the day_in_month part of expressions set to 0 should fail?
I only tested it for the weekly
keyword as shown below.
Python 3.6.9 (default, Nov 7 2019, 10:44:02)
In [1]: import pandas as pd
In [2]: import crython
In [3]: crython.__version__
Out[3]: '0.2.0'
In [5]: crython.expression.CronExpression.new('0 0 0 * * 0 *').matches(pd.Timestamp('2020-01-26 00:00:00'))
Out[5]: True
In [6]: crython.expression.CronExpression.new('0 0 0 0 * 0 *').matches(pd.Timestamp('2020-01-26 00:00:00'))
Out[6]: False
In [7]: crython.expression.CronExpression.new('@weekly').matches(pd.Timestamp('2020-01-26 00:00:00'))
Out[7]: False
Matches are always? false when performing a CSV style check but the individual items are strings, not int.
Hi ๐
This is my first visit to this fine repo, but it seems you have been working hard to keep all dependencies updated so far.
Once you have closed this issue, I'll create separate pull requests for every update as soon as I find one.
That's it for now!
Happy merging! ๐ค
I just want to check in on this one, as I expect a different behaviour.
From the docs, we have:
# fire every 10 seconds
@crython.job(second=range(0,60,10))
which is true and good behaviour. However from that I expected the same use for minutes:
# fire every 10 minutes
@crython.job(minute=range(0,60,10))
But as second= defaults to '*', we actually get:
# fire every second of every 10th minute
@crython.job(minute=range(0,60,10))
Is this intended?
This issue tracks work for making Windows a first class citizen for this package.
I've defined this example script main_foo.py
which dies just after I execute it with python main_foo.py
. If I enable that infinite while
loop currently commented out at the bottom of the following example, then I see the script staying alive and printing logging statements as expected.
I have 2 questions:
while
loop the expected way to keep alive the script? I was expecting the library was taking care itself of keeping the script alive with some sort of blocking infinite loop and I was surprised I had to take care of it myself, so I am wondering if I am using it the right way or is there a recommended way to do this?first_func()
in the following example which could potentially take more time than the recurrence at which it is scheduled. If the code inside first_func()
is mainly network I/O (REST APIs) and numpy
/ pandas
calculations (done in native C), then I should be good to go with crython
invoking it multiple times even if some old executions still have to complete. I am assuming crython
is running first_func()
in a separate thread at each match of the crontab string (e.g. '*/5 * * * * * *'
), so whenever this first_func()
is finished the thread will die and crython
will go on with no hiccups. Given that there is no CPU intensive code running in python (because the CPU intensive part is done in C), then I shouldn't be blocking the main thread of the main process, right? With this setup I should not mess with the GIL, I think.import crython
import time
import sys
import logging
logging.basicConfig(
format='%(asctime)s %(processName)-10s %(levelname)-6s %(message)s',
level=logging.DEBUG,
stream=sys.stdout
)
# every 5 seconds
@crython.job(expr='*/5 * * * * * *')
def first_func():
logging.info("start 1st func")
time.sleep(3) # but this could sometimes take more than 5 seconds
logging.info("finish 1st func")
# every minute at seconds 1, 5 and 10
@crython.job(expr='1,5,10 * * * * * *')
def second_func():
logging.info("2nd func")
if __name__ == "__main__":
crython.start()
# TODO is the following needed?
# while True:
# time.sleep(1)
Currently, the tests in the multi-module-refactor
branch mostly just test against the second
field partial. This means that most fixtures are setup to create values based on the min/max/specials allowed by the second
field.
Ideally, we want to parameterize all of the tests so we can feed in a field (or partial) with the valid min/max/specials and use the same test methods for all field types, not just second
.
I'm seeing this in the multi-module-refactor
branch but likely a pre-existing bug and not a regression.
>>> from crython import field
>>> sec = field.second('10-26/8')
>>> sec.matches(10)
False
>>> sec.matches(18)
False
>>> sec.matches(14)
True
Here is the code
`import crython
#Fire every second.
@crython.job(second='*/10')
def foo():
print ( "I'm Homer Simpson. -- Grimey" )
if name == "main":
crython.start()`
Here is the result
Traceback (most recent call last):
File "ctest.py", line 3, in
@crython.job(second='*/10')
File "/Users/pete/lib/python3.5/site-packages/crython/job.py", line 27, in job
fields = dict((k, kwargs.pop(k)) for k in kwargs.keys() if k in field.NAMES)
File "/Users/pete/lib/python3.5/site-packages/crython/job.py", line 27, in
fields = dict((k, kwargs.pop(k)) for k in kwargs.keys() if k in field.NAMES)
RuntimeError: dictionary changed size during iteration
Test script:
#!/usr/bin/env python
import crython
import time
@crython.job(second='*/3')
def foo():
print("I'm using */3 syntax.")
@crython.job(second=range(0, 60, 2))
def bla():
print("I'm using range(0, 60, 2).")
if __name__ == '__main__':
crython.start()
try:
while True:
time.sleep(0.2)
except KeyboardInterrupt:
pass
print("Done")
Prints:
I'm using range(0, 60, 2).
I'm using range(0, 60, 2).
I'm using range(0, 60, 2).
... etc ...
I would expect "I'm using */3 syntax.
" to be printed every three seconds also, but it's not.
Is this a bug or am I doing something wrong ?
Latest master and pypi 0.0.4 version.
Hello, we are running crython in production using virtual enviroment, and now we need version 0.0.8 (for the @reboot, annotation), but version 0.0.8 is not available on pypi, and we would prefer not include a manual build for dependencies in our build process.
Is it possible to to upload the newest version of crython to pypi?
https://pypi.org/project/crython/#history
Add a "subprocess" context as a simple shortcut for subprocess.Popen
instead of requiring users to write it themselves.
The initial thought it to just feed the result of the function directly into the subprocess.Popen
call. However, we'll want to provide a way to pass *args
and **kwargs
down as well.
@crython.job(ctx='subprocess')
def cat(path):
return 'cat {}'.format(path)
I am trying to change the logging level of the whole crython
package, but this does not help:
# first
logging.basicConfig(
format='%(asctime)s %(threadName)s %(funcName)-10s %(levelname)-6s %(message)s',
level=logging.getLevelName("DEBUG"), # ATTENTION this string comes from a configuration file
stream=sys.stdout
)
# then
crython_log = logging.getLogger("crython")
crython_log.setLevel(logging.INFO)
crython_log.propagate = True
# finally
@crython.job(expr="0 0 * * * * *")
def my_scheduled_func():
# TODO do stuff
logging.debug("do stuff")
How do I change the logging level only for the crython
package?
The weekday
field should be support numeric range 0-7
in order to support zero and one based inputs.
Normally, the inputs are 0-6
with Sunday being zero and Saturday being six. However, Sunday being seven is also a valid possibility.
As discussed in #262 , the crython
module interface does not expose a mechanism to block/join on the default (global) CronTab instance. This makes processes that only run scheduled jobs significantly harder to write as well as any that don't block by binding to a socket.
Considerations:
Add an examples.py
file that contains working examples that go beyond those in the README.
hello
is this script available for multi threading or multiprocess jobs ?
Issue #249 brought up the question about running in multi-threaded/multi-process environments.
This is supported but incorrectly documented. The README should include a example of setting both thread
and multiprocess
contexts and not use the old, deprecated process
value.
Hello, let me start off by saying I'm a bit of a python beginner so excuse me if there's a well-documented way to solve this.
I noticed that if an exception occurs while a job is happening, the stack trace is not shown on the console. I wanted to pipe that output into a file or something so I can review, or better yet, pipe all exception stack traces to a function that logs to slack.
Is there a way to disable the exception output suppression?
the way to start the tab fot this version is
crython.start()
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.