2

I'm trying to modify flask request callback so it can communicate with other code while executing the callback. The example explains it better:

from flask import Flask, request
from queue import Queue

flask_input_queue = Queue()
flask_output_queue = Queue()
app = Flask(__name__)


@app.route("/voice", methods=['GET', 'POST'])
def voice():
    # The receiver on the other end gets notified we got a request
    flask_output_queue.put(str(request))

    # This blocks until the external party responds with something
    response = flask_input_queue.get()

    # But how do the queues end up in the function scope to begin with?
    return response


app.run(debug=True)

Here the external code would have a channel using the queues into the web server. This allows me to completely abstract the concept of the web server on the other part of the code.

However for that, I need to be able to pass information to the callback method in ways other that just URLs. Frankly it doesn't have to be a queue other IPC mechanisms will also work ok but they all rely on having a way to pass data into the callback.

Is there a way to do that in flask?

1 Answer 1

3

The _URLCallbackClass in combination with add_url_rule is used instead of the decorator. That _URLCallbackClass gets the queue as instance attributes. Given that the actual callback function is the method of _URLCallbackClass, we smuggled the queues into the callback function.

The rest of the complexity just arises from providing a working example.

logging.basicConfig(format='[Thread: %(threadName)s-%(thread)d] %(message)s', level=logging.INFO)                                                                                                             [0/0]
logger = logging.getLogger(__name__)


class ControllableServer(threading.Thread):

    class _URLCallbackClass():
        def __init__(self, input_queue, output_queue):
            self.input_queue = input_queue
            self.output_queue = output_queue

        def url_callback(self):
            self.output_queue.put("[URL callback] I just got called")
            response_from_the_queue = self.input_queue.get()
            return Response(response_from_the_queue, 200)

    def __init__(self, input_queue, output_queue):
        super().__init__(daemon=True)
        self.input_queue = input_queue
        self.output_queue = output_queue
        self._flask = Flask(__name__)

    def run(self):
        callback_class = ControllableServer._URLCallbackClass(self.input_queue, self.output_queue)
        self._flask.add_url_rule('/endpoint', 'url_callback', callback_class.url_callback)
        logger.info(f"Starting flask")              
        self._flask.run()                           


def call_URL_in_separate_thread(url):               
    def call_URL(url):                              
        logger.info(f"Calling {url}")               
        response = requests.get(url)                
        logger.info(f"Got response: {response.text}")                                                    
        return response.text                        

    url_caller_thread = threading.Thread(target=call_URL, args=(url,))                                   
    url_caller_thread.start()                       


if __name__ == "__main__":                          
    flask_input_queue = Queue()                     
    flask_output_queue = Queue()                    
    controllable_server = ControllableServer(flask_input_queue, flask_output_queue)                      
    controllable_server.start()                     
    call_URL_in_separate_thread("http://127.0.0.1:5000/endpoint")                                        
    message_from_within_the_callback = flask_output_queue.get()                                          
    logger.info(f"Got message from queue: {message_from_within_the_callback}")                           
    message_to_the_callback = "I come from the outside !@##$@"                                           
    flask_input_queue.put(message_to_the_callback)  
    logger.info(f"Sending message to queue: {message_to_the_callback}")                                  

Output:

[Thread: Thread-1-140465413375744] Starting flask
[Thread: Thread-2-140465404983040] Calling http://127.0.0.1:5000/endpoint
 * Serving Flask app "basic_flask_passing_variable" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
[Thread: Thread-1-140465413375744]  * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
[Thread: MainThread-140465450415936] Got message from queue: [URL callback] I just got called
[Thread: MainThread-140465450415936] Sending message to queue: I come from the outside !@##$@
[Thread: Thread-3-140465396041472] 127.0.0.1 - - [03/Mar/2020 18:33:32] "GET /endpoint HTTP/1.1" 200 -
[Thread: Thread-2-140465404983040] Got response: I come from the outside !@##$@
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.