rbonghi / jetson_stats

📊 Simple package for monitoring and control your NVIDIA Jetson [Orin, Xavier, Nano, TX] series
https://rnext.it/jetson_stats
GNU Affero General Public License v3.0
2.14k stars 261 forks source link

Using with statement does not terminate jtop service after execution exits the scope #340

Closed jkompis closed 1 year ago

jkompis commented 1 year ago

Describe the bug Hello, I have following simplified code, it simulates REST API that is being called by clients to get current status of Jetson device. Problem is that each "client call" spawns new jtop service that is not closed afterwards even though in source code there is a claim that .close() is not necessary when used with with statement. When I un-comment jetson.close() line jtop services are closed as expected.

To Reproduce

from jtop import jtop

if __name__ == "__main__":

  while True:
    with jtop() as jetson:
        print(jetson.uptime)
        # without this line jtop services keeps piling up
        # jetson.close()

Expected behavior There is no need to call jetson.close() in order to terminate jtop service.

Additional context N/A

Board

Jetpack

Jetson-Stats

rbonghi commented 1 year ago

Hi @jkompis

Welcome on board! :-) You don't need to use the statement jetson.close()when you work with with jtop() as jetson the statement with will automatically close the connection.

Reading your code, I suggest using the call jetson.ok()

from jtop import jtop

if __name__ == "__main__":

    with jtop() as jetson:
        while jetson.ok():
             print(jetson.uptime)

Note: I am updating the documentation #338 to make it more readable and usable than now. Keep ready for next week :smile:

Hints:

The statement jetson.close() may be used when you work with jtop in a callback routine, like this example:

jetson = jtop()
jetson.start()
stat = jetson.stats
jetson.close()

you can also use jtop in a callback routine

def read_stats(jetson):
    print(jetson.stats)

# Open the jtop
jetson = jtop()
# Attach a function where you can read the status of your jetson
jetson.attach(read_stats)
jetson.loop_for_ever()
jkompis commented 1 year ago

Hello @rbonghi, thank you for your fast response!

I think I did not describe my issue good enough, I will put here example that is more close to what I am trying to achieve. It is simple Flask REST API that returns uptime upon request. However problem with this code is that it keeps jtop process open after the call, so say after 100 requests I end up with 100 jtop processes still open. But this is strange as I am using with jtop() as jetson: that should close it after request is processed.

from flask import Flask
from jtop import jtop
import json

app = Flask(__name__)

@app.route('/status')
def status():
  response = {}
  with jtop() as jetson:
    response['uptime'] = str(jetson.uptime)
  return json.dumps(response)

Using approach you mentioned, everything works fine:

from flask import Flask
from jtop import jtop
import json

app = Flask(__name__)

@app.route('/status')
def status():
  jetson = jtop()
  jetson.start()
  response = {}
  response['uptime'] = str(jetson.uptime)
  jetson.close()
  return json.dumps(response)
rbonghi commented 1 year ago

I wrote ages ago about the Flask service, and I'm not also so expert, but I'm not honestly an expert in this world. Below I made an example of using Flask and jtop inside an object. I don't remember an exit function without CTRL-C, and I didn't test it. I hope that I have helped you now.

BTW: If it works, let me know, and I will add this example in my example folder

from flask import Flask, Response
from jtop import jtop
import json

class WebService:

    def __init__(self):
        # Load Service
        self._app = Flask(__name__)
        # Register update function
        self._app.add_url_rule('/status', 'status', self.status)
        # Initialize jtop
        self._jetson = jtop()
        # start service
        self.start()

    def status(self):
        response = {}
        # Get uptime
        response['uptime'] = str(self._jetson.uptime)
        # Spin jtop
        self._jetson.ok(spin=True)
        # return data
        return Response(
            response=json.dumps(response),
            status=201,
            mimetype="application/json"
        )

    def start(self):
        print("Init server ...")
        # Start jtop
        self._jetson.start()
        # Start server
        self._app.run(debug=True)

    def stop(self):
        print("switch off server")
        # Stop jtop
        self._jetson.stop()
        # Stop server

if __name__ == "__main__":
    # Initialize service
    service = WebService()
    service.stop()
rbonghi commented 1 year ago

I made some fixes on my previous code in particular the function self._jetson.ok(spin=True)

jkompis commented 1 year ago

Thank you, your example works even better since it does not start new jetson for each request. The only issue I think is self._jetson.stop() part as it should be self._jetson.close() since else it gives you an error on exit.

rbonghi commented 1 year ago

I'm happy this example helped you!

I will fix it and add it to my example list :-)