kramer65
kramer65

Reputation: 53993

Python Apscheduler cron job from loop doesn't do all different versions

I've got a function which gets and stores something from an exchange every minute. I run the functions using the (normally excellent) APScheduler. Unfortunately, when I add cron jobs from a loop, it doesn't seem to work as I expect it to.

I've got a little list with a couple strings, for which I want to run the getAndStore function. I could do this like so:

from apscheduler.scheduler import Scheduler
apsched = Scheduler()
apsched.start()
apsched.add_cron_job(lambda: getAndStore('A'), minute='0-59')
apsched.add_cron_job(lambda: getAndStore('B'), minute='0-59')
apsched.add_cron_job(lambda: getAndStore('C'), minute='0-59')

This works fine, but since I'm a programmer and I love to automate stuff, I do this:

from apscheduler.scheduler import Scheduler
def getAndStore(apiCall):
    # does a call to the api using apiCall as a value
    # and stores it in the DB.
    print apiCall

apiCalls = ['A', 'B', 'C']

apsched = Scheduler()
apsched.start()
for apiCall in apiCalls:
    print 'Start cron for: ', apiCall
    apsched.add_cron_job(lambda: getAndStore(apiCall), minute='0-59')

When I run this, the output is the following:

Start cron for:  A
Start cron for:  B
Start cron for:  C
C
C
C

The strange thing is that it appears to start it for A, B and C, but it actually starts a cron for C three times. Is this a bug in APScheduler? Or am I doing something wrong here?

All tips are welcome!

Upvotes: 2

Views: 2280

Answers (2)

devramon22
devramon22

Reputation: 44

This worked for me:

for apiCall in apiCalls:

    print 'Start cron for: ', apiCall

    action = lambda x = apiCall: getAndStore(x)
    apsched.add_cron_job(action , minute='0-59')

Upvotes: -1

eg444
eg444

Reputation: 66

This annoyed me for a while until I finally figured it out. So much so, I created a stackoverflow account after years of lurking. First post!

Try dropping the lambda (I know..., I went down that route too) and pass the arguments via args as a tuple. I've used a slightly different scheduler below, but it should be easily adapted.

from apscheduler.schedulers.background import BackgroundScheduler
import time   

def getAndStore(apiCall):
    # does a call to the api using apiCall as a value
    # and stores it in the DB.
    print(apiCall)

apiCalls = ['A', 'B', 'C']

apsched = BackgroundScheduler()
apsched.start()
for apiCall in apiCalls:
    print ('Start cron for: ' + apiCall)
    apsched.add_job(getAndStore, args=(apiCall,), trigger='interval', seconds=1)

# to test
while True:
    time.sleep(2)

Output is:

Start cron for: A
Start cron for: B
Start cron for: C
B
A
C

Upvotes: 5

Related Questions