Stdin / Stdout (CGI like) service question

Hi!
I am trying to develop a service that can be called from command line and behave like a terminal.
All I type (stdin) is passed to remote service for execution, and the result is sent me back to print out to stdout.
Here is the code:

import logging
from nameko.extensions import Entrypoint
from nameko.rpc import RpcProxy


logger = logging.getLogger(__name__)

class StdinReader(Entrypoint):
    def start(self):
        self.container.spawn_managed_thread(self.run)

    def run(self):
        while True:
            s = input()
            self.handle_read(s)

    def handle_read(self, cmd):
        logger.info('Handle read %s', cmd)
        self.container.spawn_worker(self, (cmd,), {})

stdin = StdinReader.decorator

class TerminalBroker:
    name = 'terminal'
    asterisk = RpcProxy('asterisk')

    @stdin
    def read(self, cmd):
        logger.info('Read here %s', cmd)
        res = self.asterisk.cli_command(cmd)
        print(res)

I have now 2 problems here:

  1. “Handle read” is logged, but “Read here” is not. So this is like container.spawn_worker does not call the worker method read.
  1. How to fully eliminate any stdout output from nameko run?
/services # nameko run terminal_broker --config=config.yml
2019-10-19 11:16:28,892 - nameko.messaging:227 - DEBUG - starting <QueueConsumer at 0x7f04173183d0>
2019-10-19 11:16:28,892 - nameko.messaging:231 - DEBUG - waiting for consumer ready <QueueConsumer at 0x7f04173183d0>
hello
2019-10-19 11:16:30,883 - terminal_broker:18 - INFO - Handle read hello

I see that it event does not start.
I added

    @rpc
    def test(self):
        print('I am alive!')

to TerminalBroker and cannot call it (it hangs).

So if I replace

s = input()

to

eventlet.sleep(1)

the service starts normally and I can call test() from the shell.

So seems it blocks totally on input().
I tried adding

import eventlet
eventlet.monkey_patch()

but it did not help.
Digging more…

Ok found a solution:

    def raw_input(self):        
        select.select([sys.stdin], [], [])
        return sys.stdin.readline()

    def run(self):
        while True:
            s = self.raw_input()
            self.handle_read(s)

Hope this can help somebody else…

Hi @litmax,

Your solution makes sense. input() is blocking and not patched by eventlet, so will prevent the scheduler (and therefore everything else) from running.

To limit your logging output, you can configure Python’s logging module by adding a dictConfig compatible entry to your config file. See https://nameko.readthedocs.io/en/stable/cli.html#running-a-service

Thanks Matt for your advise!