What I’m trying to do:
Just learning about about background tasks to use in a project.
What I’ve tried and what’s not working:
I can start the background from the anvil.server module - the background task is remote and is started with the uplink and then access remote information using task.get_state()[‘processes’] . However if I try to kill the process (which is designed to run indefinitely using the returned task object I get an error message saying I have to do this in the server module (basically). However when I return the task object from the server module is not longer available.
I tried passing the task object back to the server module with something simple shown below.
I thought that the task ID might be a way back to the object from the server, but I see no documentation on accessing the task from the id. I really do not see any clear example of killing the task from server after started and the object return to the foreground code? I am sorry if I missed that information.
Thank you,
JM
Code Sample:
@anvil.server.callable
def stop_monitor(task):
task.kill()
# this is a formatted code snippet.
# paste your code between ```
It seems that you’re running Uplink code as a background task? Uplink code doesn’t run on the Anvil Server. The in-Server “kill” signal can’t reach it.
However, you can code your Uplink program to disconnect and terminate itself, on command, i.e., on a specific, new anvil.server.call(). Write a function, in the Uplink program, to do that, and mark it as @anvil.server.callable.
I’m not sure what the guts of that function would look like, having never coded one myself. See Disconnecting. I’m not sure whether your Uplink program will stop running by itself after the disconnect.
I see … I put the calling code in the anvil.server module – and tried this for example. I realized quickly that task was not retained after I returned it back to foreground –
So in the foreground i have (this is just testing code to learn how this works) –
and trying self.process.kill() fails. This code calls the code below which lives in the anvil.server module.
def monitor_processes(process):
task = None
if process == "start":
task = anvil.server.launch_background_task('chkpython')
print("starting server task")
return task
elif process == "stop":
print("trying to stop the process")
task.kill()
if task.get_termination_status() == "killed":
print("Yes, the task was killed!")
return "done"
else:
print("failed to find start or stop")
this code calls the code on remote server down the uplink… And that code is simply looking at python running processes to identify starts and stops of code of interest …
That code is below – please if it is not much work tell me if this is the wrong procedure to run the remote code…
@anvil.server.background_task
def chkpython():
# add a list of process that should not run at the same time : next one python buildpost.py
print (f"checking for an existing instance of this software ...")
# show processes
waitforprocessess = ["buildpost.py","truthmafia_wploginapi.py","startsingletranscript.py","masterproai_uplink_v1.py",
"startsinglefeedbuildpost","startbuildpost.py"]
while True:
try:
results = None
total_processes_found = []
cit = subprocess.check_output(['ps', '-df'])
kit = subprocess.check_call(['ps', '-df'])
#print(str(cit))
for process in waitforprocessess:
print (f"the process {process}")
# .?(python).*(masterproai_uplink_v1.py).*
candidate = f"(.?(python).*({process}))"
results = re.findall(candidate,str(cit))
if results:
total_processes_found.append(results[0][2])
if total_processes_found:
print(f"Currently Running: {total_processes_found}, will wait till next time.")
anvil.server.task_state['processes'] = total_processes_found
#return True
else:
print(f"No running instances found ")
#return False
time.sleep(2)
except Exception as e:
print (f"exception trying to check for running process {str(e)}")
return
When you say “remote server”, it isn’t clear to me which computer you mean. It’s often been used to mean either one of the following:
The Anvil Server
The computer running your Uplink program
…probably because both provide functions via @anvil.server.callable, which are called via anvil.server.call(). But for a specific case, to be debugged, it really helps to be a bit more precise. These locations are on two different computers, with different memory contents, and communicating only intermittently via Internet, when an anvil.server.call() from one to the other is executed.
It’s not clear to me which code is running where. But I suspect that kill only works within a single computer. That is, the program that invokes kill must be running on the same computer as the background task that it wants to stop.
I don’t use background tasks enough to be sure, though. Others here on the forum will almost certainly know.
Remote Code (living down the uplink pipe) @anvil.server.background_task
def chkpython():
do a while loop and send data back to foreground (which works)
My primary question, please, is this: Is this the correct procedure and if so how does one Kill the remote background task?
@anvil.server.callable
def monitor_processes(process):
task = None
if process == "start":
task = anvil.server.launch_background_task('chkpython')
print("starting server task")
return task
elif process == "stop":
print("trying to stop the process")
task.kill()
if task.get_termination_status() == "killed":
print("Yes, the task was killed!")
return "done"
else:
print("failed to find start or stop")
if you call
anvil.server.call('monitor_processes', 'stop')
then, in monitor_processes, its local variable task will be None at the time it tries to call task.kill(). Local variables are deleted at the end of the call, and even if they weren’t, any earlier value would be set to None at the function’s first line of code.
This is better off handled by a separate function:
which receives the identity of the intended task. Of course, in order for the Client (browser program) to have the task id in the first place, whatever created the background task would have to return it, e.g.,
Uncertainty: I would expect .kill() might take a second or two. This may mean that .get_termination_status()might not be immediately valid; I’m not sure, I haven’t tried it.
That is what I was looking for – I looked for documentation that showed how to access the background task with the ID – if it is there I missed it – I understand now… thank you Phil.