Inconsistent Behaviour while executing a Background Task in Flask Web App - python

I am creating a flask web app which has a background task of making an API Calls every x seconds.The interval is decided based on a value coming from the API,if the value is True then and if the database don't have any data for counter it will insert a counter value 1.If it has a counter value it will increment the counter and update it on the database and the next call for this task will be after 40 seconds but if it is false the the next call will be in 10 seconds.Here is my code
import time
import threading
def writemotiondata():
processing = False
while True:
deviceid = 'eb4f7839b63063bdec3ikc'
openapi = authorization()
openapi.connect()
response = openapi.get("/v1.0/devices/{}".format(deviceid))
result = response['result']
status = result['status']
value = status[0]['value']
print(value)
if (value == True):
tempdata = motiondata.find()
previousdata = [{item: key[item] for item in key if item != '_id'} for key in tempdata]
if len(previousdata) == 0:
data = {"sensorname": "pir",
"numberofpeople": 1}
motiondata.insert_one(data).inserted_id
else:
count = previousdata[0]['numberofpeople']
count += 1
filter = {"sensorname": "pir"}
updateddata = {"$set": {"numberofpeople": count}}
motiondata.update_one(filter, updateddata)
time.sleep(40)
else:
time.sleep(10)
if __name__ == '__main__':
t1 = threading.Thread(target=writemotiondata)
t1.start()
app.run(debug=True)
Here the expected output is if the value is True the task should increment the counter and update the database.For example if the previous count was 1,after completing the task the new count should be 2 and the task should be called to execute again in 40 seconds. If the value is false the task will be called again in 10 seconds.
However The output I am getting is the counter in my database gets incremented inconsistently,sometimes it gets incremented by 1 ,sometimes it gets incremented by 2 or 3.I have printed out the value and saw in 40 seconds sometimes the value true is being printed 2/3 times instead of one,same goes for false.Basically the task is being executed more than once,in that time interval.Can anyone please help me figure out why is this happening and what I am doing wrong.
I am using a single thread,no more threads has been used in the code.

Related

Why is my dictionary not updating in this while loop?

Running: Python 3.9.9 and Django 4
I'm trying to put together a loop that waits for a users input and then appends that input to an existing dictionary. See code below:
def calculator(request):
loop_int = 1
numbers = [str(x) for x in range(0,10)]
i = "1"
current_nums = {'1':[],'2':[]}
if request.GET: #wait for request.GET to return True before starting while loop
while loop_int < 10:
r = request.GET #store request.GET object as r
if r: #this is here to stop the loop and wait for request.GET to return True
print(r)
if list(r.values())[0] in numbers:
digit = list(r.values())[0] #grab the value from request.GET
current_nums[i].append(digit) #append that value to the list at "1" in current_nums dictionary
print(f'digit = {digit}')
print(f'current_nums = {current_nums}')
loop_int += 1 #increment the loop_int
request.GET = None
return render(request, 'calculator/calculator.html')
The last print statement print(f'current_nums={current_nums}') displays the updated dictionary that I expect, but the appended digits don't persist through the next iteration of the loop. Code output below:
<QueryDict: {'1': ['1']}>
digit = 1
current_nums = {'1': ['1'], '2': []}
<QueryDict: {'2': ['2']}>
digit = 2
current_nums = {'1': ['2'], '2': []}
This file is a views.py file for a Django project. I'm having no issues (as far as I can tell) getting the information from the front end using request.GET.
One odd thing I discovered is that if I remove the statement request.GET = None at the end of the loop, which allows the loop to run uninterrupted with the same value for request.GET, then the program works as intended for the next 9 iterations and the dictionary updates persist. However, as soon as I try to set request.GET = None to pause the loop and wait for a legitimate user input, the dictionary updates stop persisting.
Am I making a simple scope error? Or is there a nuance to request.GET that I'm missing?
Your problem is that you put current_nums in the view function, and every time a request comes in, it will be initialized.
You can put it outside the view function, like below, and it will save the data added with each request.
class Data:
loop_int = 1
current_nums = {'1':[],'2':[]}
numbers = [str(x) for x in range(0,10)]
def calculator(request):
i = "1"
if request.GET and Data.loop_int < 10: #wait for request.GET to return True before starting while loop
r = request.GET #store request.GET object as r
print(r)
if list(r.values())[0] in Data.numbers:
digit = list(r.values())[0] #grab the value from request.GET
Data.current_nums[i].append(digit) #append that value to the list at "1" in current_nums dictionary
print(f'digit = {digit}')
print(f'current_nums = {Data.current_nums}')
Data.loop_int += 1 #increment the loop_int
return render(request, 'calculator/calculator.html')
You can still use it for a single person to test locally. If it involves multiple concurrency, you need to lock it.

How to match current date and specific date in Python

I'm developing a reminder app in Python. My question is when I execute my code. It should wait until current date equals to specific date. But it's not working, here's my code.
CODE:
from threading import Thread
from datetime import datetime, timedelta
# Current date, 8/15/2020 - 10:00
a = datetime.now()
# Specific date (1 minute later from current date), 8/15/2020 - 10:01
b = a + timedelta(minutes = 1)
# Reminder name
d = "stack reminder"
# Reminder list
c = {}
# Target function
def createThread():
while True:
if(b.second == a.second and
b.minute == a.minute and
b.hour == a.hour and
b.day == a.day and
b.month == a.month and
b.year == a.year):
print("worked")
# If thread name in reminder list
if d in c:
print("canceling")
t.cancel()
break
# Set thread and thread name and print thread name
t = Thread(target = createThread)
t.setName(d)
print(t.getName())
# Append reminder name to reminder list and print
c[d] = b
print(c)
# Start thread
t.start()
This code isn't working. Is if statement wrong? I'm creating Thread because while program waiting for specific date, I want to do different things. Where is my fault and how to run this code?
You are never updating the a variable again.
datetime.now() doesn't constantly update so you will have to call this in your thread.
a = datetime.now() in every iteration of your while loop.
At the moment you are never getting get your if condition to match as the time in a stays in the past.
Also you should be able to simplify this.
(b.second == a.second and
b.minute == a.minute and
b.hour == a.hour and
b.day == a.day and
b.month == a.month and
b.year == a.year):
To just simply
if b == a:
As both should be datetimes.
But its probably better to do use > in your condition as by using == you would have to match to the millisecond. Even matching to the second could cause issues and the condition might be missed.
i.e
If "a" (i.e the current time) >= "b" the time you want to check for.
Then fire the condition.
or put another way... If the current time is greater than or equal to the calendar entry time - then its time to alert the user.
if a >= b:
Complete Example:
from threading import Thread
from datetime import datetime, timedelta
# Current date, 8/15/2020 - 10:00
# Specific date (1 minute later from current date), 8/15/2020 - 10:01
b = datetime.now() + timedelta(minutes = 1)
# Reminder name
d = "stack reminder"
# Reminder list
c = {}
# Target function
def createThread():
while True:
a = datetime.now()
if a > b :
print("worked")
# If thread name in reminder list
if d in c:
print("canceling")
t.cancel()
break
# Set thread and thread name and print thread name
t = Thread(target = createThread)
t.setName(d)
print(t.getName())
# Append reminder name to reminder list and print
c[d] = b
print(c)
# Start thread
t.start()

Performing a task based in specific time interval in python

I am trying to switch on and off the LED based on a set set_car_id returning some value within a time interval. If the set returns some value, i want the LED to be brighter for 8 seconds. In the code shown below, once the set returns a value, the LED is switched on for 8 seconds. But, if the set returns a value at 5 second (within the 8 sec), then the LED won't be switched on till next 13 sec, it will be on for 3 more seconds and then suddenly switches off. I am showing only smaller part of the code. Any suggestions to solve?
last_bright_time = None
last_dim_time = None
new_action = -1
def LED_control(set_car_id):
global last_bright_time
global last_dim_time
curr_time = time.time()
should_remain_bright = False
should_remain_dim = False
if (new_action == 0): #new_action ==0 corresponds to set_car_id returning some value
if last_bright_time == None:
last_bright_time = time.time()
if (curr_time - last_bright_time) < 8:
should_remain_bright = True
if ((len(set_car_id) > 0) or should_remain_bright = True):
car_light(1) # function to bright the LED
last_dim_time = None
else:
car_light(0) # function to dim the LED
last_bright_time = None
Try this:
import time
while True:
brighten()
time.sleep(8)
dim()
time.sleep(8)
If you want something more precise:
import time
def sleep():
time_start = time.time()
while time.time() < time_start + 8000:
pass
while True:
brighten()
sleep()
dim()
sleep()
In the pieces of code above, you have to define the brighten and dim functions.

Multiprocessing: How to determine whether a job is waiting or submitted?

Background
A small server which waits for different types of jobs which are represented
as Python functions (async_func and async_func2 in the sample code below).
Each job gets submitted to a Pool with apply_async and takes a different amount of time, i.e. I cannot be sure that a job which was submitted first, also finishes first
I can check whether the job was finished with .get(timeout=0.1)
Question
How I can check whether the job is still waiting in the queue or is already running?
Is using a Queue the correct way or is there a more simple way?
Code
import multiprocessing
import random
import time
def async_func(x):
iterations = 0
x = (x + 0.1) % 1
while (x / 10.0) - random.random() < 0:
iterations += 1
time.sleep(0.01)
return iterations
def async_func2(x):
return(async_func(x + 0.5))
if __name__ == "__main__":
results = dict()
status = dict()
finished_processes = 0
worker_pool = multiprocessing.Pool(4)
jobs = 10
for i in range(jobs):
if i % 2 == 0:
results[i] = worker_pool.apply_async(async_func, (i,))
else:
results[i] = worker_pool.apply_async(async_func2, (i,))
status[i] = 'submitted'
while finished_processes < jobs:
for i in range(jobs):
if status[i] != 'finished':
try:
print('{0}: iterations needed = {1}'.format(i, results[i].get(timeout=0.1)))
status[i] = 'finished'
finished_processes += 1
except:
# how to distinguish between "running but no result yet" and "waiting to run"
status[i] = 'unknown'
Just send the status dict, to the function, since dicts are mutable all you need to do is change a bit your functions:
def async_func2(status, x):
status[x] = 'Started'
return(async_func(x + 0.5))
Of course you can change the status to pending just before calling your apply_async

Avoding maximum recursion depth

I have the following codes which will be running 24 hours but only after 10-20 minutes I get error maximum recursion depth reached. My code is folowing
def startEnd():
flag = 0
f = open('file')
lq = f.readlines()
cur2 = lq[0]
cur1 = datetime.datetime.now()
while flag == 0:
if cur1 == cur2: # cur2 is datetime read from file
q.put(True)
flag = 1
else:
flag = 0
startEnd()
How can I avoid recursion in the following code? I need to come out of while loop since cur2 value changes.
My other question is that will following code will also lead to recursion depth error in the long run since my code need to be run 24 hours.
def planIncr():
f=open('input.txt')
lines=f.readlines()
cycle_time = int(lines[1])
f.close()
q2.put(True)
threading.Timer(cycle_time, planIncr).start()
Regarding the first function - just put everything inside a while loop:
def startEnd():
while True:
flag = 0
f = open('file')
lq = f.readlines()
cur2 = lq[0]
cur1 = datetime.datetime.now()
while flag == 0:
if cur1 == cur2: # cur2 is datetime read from file
q.put(True)
flag = 1
else:
flag = 0
Note that your second function is not recursive - it will never trigger a recursion depth error. Yes, planIncr is passed to threading.Timer, but not executed by that call. planIncr is executed by some other thread later, and the thread that called planIncr to begin with sees planIncr return right away.

Categories