0

I develop a nameko http micro servie, and it can run well, but if I replace the file myhttp.py with a cyphon compiled file named myhttp.py, I will get [curl: (7) Failed to connect to localhost port 8000: Connection refused],please help me.

step 1: use the below 3 files(build.bat,setup.py,myhttp.py) to generate myhttp.pyd

build.bat

python setup.py build_ext --inplace

setup.py

from setuptools import setup
from Cython.Build import cythonize

setup(
    name = 'myapp',
    ext_modules=cythonize("myhttp.py"),
    zip_safe=False,
)

myhttp.py

from nameko.web.handlers import http
import json
class MyHttpService:
    name = 'my_http_service'
    
    @http('POST','/hello')  #curl -i -d "world" localhost:8000/hello
    def hello(self, request):
        return "Hello, {}!".format(request.get_data(as_text=True))
    
    

step 2: use the below 3 files(installer.bat, namekorun.py, namekorun.spec) and generated myhttp.pyd just now to generate namekorun.exe

installer.bat

pyinstaller --noconfirm namekorun.spec

namekorun.py

import eventlet; 
eventlet.monkey_patch()
from nameko.runners import ServiceRunner
import myhttp
import signal


runner = ServiceRunner(config={'WEB_SERVER_ADDRESS': '0.0.0.0:8000'})
runner.add_service(myhttp.MyHttpService)


def shutdown(signum, frame):
    # signal handlers are run by the MAINLOOP and cannot use eventlet
    # primitives, so we have to call `stop` in a greenlet
    eventlet.spawn_n(runner.stop)

signal.signal(signal.SIGTERM, shutdown)
runner.start()
runnlet = eventlet.spawn(runner.wait)
while True:
    try:
        runnlet.wait()
    except OSError as exc:
        if exc.errno == errno.EINTR:
            # this is the OSError(4) caused by the signalhandler.
            # ignore and go back to waiting on the runner
            continue
        raise
    except KeyboardInterrupt:
        print()  # looks nicer with the ^C e.g. bash prints in the terminal
        try:
            runner.stop()
        except KeyboardInterrupt:
            print()  # as above
            runner.kill()
    else:
        # runner.wait completed
        break
    
    
    

namekorun.spec

   # -*- mode: python ; coding: utf-8 -*-
    
    
    block_cipher = None
    
    
    partylibs = ['nameko.constants','nameko.containers','nameko.contextdata','nameko.dependency_providers','nameko.events','nameko.exceptions','nameko.extensions','nameko.log_helpers','nameko.messaging','nameko.rpc','nameko.runners','nameko.serialization','nameko.timer','nameko.amqp.publish','nameko.cli.actions','nameko.cli.backdoor','nameko.cli.code','nameko.cli.commands','nameko.cli.main','nameko.cli.run','nameko.cli.shell','nameko.cli.show_config','nameko.standalone.events','nameko.standalone.rpc','nameko.testing.pytest','nameko.testing.rabbit','nameko.testing.services','nameko.testing.utils','nameko.testing.waiting','nameko.testing.websocket','nameko.utils.retry','nameko.utils.concurrency','nameko.web.handlers','nameko.web.server','nameko.web.websocket']
    
    partylibs += ['eventlet','eventlet.hubs.epolls','eventlet.hubs.kqueue','eventlet.hubs.selects']
    partylibs += ['dns','dns.dnssec','dns.e164','dns.hash','dns.namedict','dns.tsigkeyring','dns.update','dns.version','dns.zone']
    
    a = Analysis(['namekorun.py'],
                 pathex=[],
                 binaries=[],
                 datas=[],
                 hiddenimports=partylibs,
                 hookspath=[],
                 hooksconfig={},
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher,
                 noarchive=False)
    pyz = PYZ(a.pure, a.zipped_data,
                 cipher=block_cipher)
    
    exe = EXE(pyz,
              a.scripts, 
              [],
              exclude_binaries=True,
              name='namekorun',
              debug=False,
              bootloader_ignore_signals=False,
              strip=False,
              upx=True,
              console=True,
              disable_windowed_traceback=False,
              target_arch=None,
              codesign_identity=None,
              entitlements_file=None )
    coll = COLLECT(exe,
                   a.binaries,
                   a.zipfiles,
                   a.datas, 
                   strip=False,
                   upx=True,
                   upx_exclude=[],
                   name='namekorun')
           

step 3: start dist/namekorun/namekorun.exe, then type curl -i -d "world" localhost:8000/hello in a command window, and got curl: (7) Failed to connect to localhost port 8000: Connection refused, if replace myhttp.pyd with myhttp.py, it run well

my package as below and use vs2015

Package Version
python 3.6.8
Cython 3.0.0a9
decorator 4.4.2
eventlet 0.25.1
kombu 4.6.8
nameko 2.12.0
pyinstaller 4.7
pyinstaller-hooks-contrib 2021.4
wjh
  • 1
  • 1
  • 1
    I think you could simplify this a little. Is the Pyinstaller step actually necessary for this problem? Does it work if run from Python directly? – DavidW Jan 05 '22 at 08:07
  • @DavidW I just had a try.It does not work, After Compiled into `pyd`(`.so` on linux).And set logging level into `DEBUG`,but it show nothing when do `curl` which was refused. – lanhao945 Jan 05 '22 at 08:20
  • if the `myhttp.py` not compiled by `cython`,and just call other part (compied by `cython`,demo function) in the `hello` method will work well.Any mistake during the `nameko` registe the function,by `http` decorator? – lanhao945 Jan 05 '22 at 09:11
  • Thank HaoLan too! for your patience, reproduce my error. – wjh Jan 06 '22 at 02:01

1 Answers1

1

Tracing through the definition of nameko.web.handlers.http:

setattr(fn, ENTRYPOINT_EXTENSIONS_ATTR, descriptors)

Essentially it's trying to set attributes on the function object. Cython functions are a different class to regular Python functions, and that class doesn't have an instance dictionary so setattr will fail (I'm slightly surprised you don't get an obvious error about this).

I therefore would not expect this code to work when compiled with Cython.

DavidW
  • 29,336
  • 6
  • 55
  • 86
  • Thanks DavidW again! let me know that method is infeasible. I will give up the compiling myhttp.py. in fact, my aim is to hide python source code, as most of files have compiled successfully, not compiling the file is nothing serious. I have finished my tasks. – wjh Jan 06 '22 at 01:55