nameko http micro service run fail with cyphon compiled pyd file but py file well

149 views Asked by At

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
1

There are 1 answers

1
DavidW On

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.