Bogdanp / django_dramatiq

A Django app that integrates with Dramatiq.
https://dramatiq.io
Other
331 stars 77 forks source link

Executable name for Dramatiq on Windows is "dramatiq.exe" #109

Open pkimber opened 3 years ago

pkimber commented 3 years ago

The _resolve_executable method in django_dramatiq/management/commands/rundramatiq.py will find venv\Scripts\dramatiq, but on Windows it needs to find venv\Scripts\dramatiq.exe

Can we update the code in: https://github.com/Bogdanp/django_dramatiq/commit/4c70775bbdd7b4a6844afeec48ddb58d3bb7275d

pkimber commented 3 years ago
  1. The python path isn't being searched because I am using subprocess.Popen

  2. The old _resolve_executable builds the path to venv\Scripts\dramatiq (as long as sys.executable returns something):

def _resolve_executable(self, exec_name):
    bin_dir = os.path.dirname(sys.executable)
    if bin_dir:
        return os.path.join(bin_dir, exec_name)
    return exec_name

The new version of _resolve_executable only updates the executable_path if the file exists (if os.path.isfile(exec_path)). For Windows, we need to look for dramatiq.exe.

pkimber commented 3 years ago

I solved the issue by adding to the _resolve_executable method in django_dramatiq/django_dramatiq/management/commands/rundramatiq.py:

# fall back to default behaviour (from earlier versions)
return os.path.join(bin_dir, exec_name)

Here is the whole method:

    def _resolve_executable(self, exec_name):
        bin_dir = os.path.dirname(sys.executable)
        if bin_dir:
            for d in [bin_dir, os.path.join(bin_dir, "Scripts")]:
                exec_path = os.path.join(d, exec_name)
                if os.path.isfile(exec_path):
                    return exec_path
            # fall back to default behaviour (from earlier versions)
            # ref https://github.com/Bogdanp/django_dramatiq/issues/109
            return os.path.join(bin_dir, exec_name)
        return exec_name

I tried to write a test, but failed. Would you like me to create a pull request for the method (without tests)?

Bogdanp commented 2 years ago

I'm confused about why the fallback would fix the problem in this case. exec_name is always either dramatiq or dramatiq-gevent so even with the fallback in place, it sounds like it would resolve to the wrong path. What am I missing?

pkimber commented 10 months ago

Not sure I am helping, but I wrote a Django management command with two versions of _resolve_executable (_resolve_executable and _resolve_executable_updated):

import os
import sys

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = "Dramatiq - process is stopping #5668"

    def _resolve_executable(self, exec_name):
        bin_dir = os.path.dirname(sys.executable)
        if bin_dir:
            for d in [bin_dir, os.path.join(bin_dir, "Scripts")]:
                exec_path = os.path.join(d, exec_name)
                if os.path.isfile(exec_path):
                    return exec_path
        return exec_name

    def _resolve_executable_updated(self, exec_name):
        bin_dir = os.path.dirname(sys.executable)
        if bin_dir:
            for d in [bin_dir, os.path.join(bin_dir, "Scripts")]:
                exec_path = os.path.join(d, exec_name)
                if os.path.isfile(exec_path):
                    return exec_path
            # fall back to default behaviour (from earlier versions)
            # ref https://github.com/Bogdanp/django_dramatiq/issues/109
            return os.path.join(bin_dir, exec_name)
        return exec_name

    def handle(self, *args, **options):
        self.stdout.write(f"{self.help}")
        executable_name = "dramatiq"
        result = self._resolve_executable(executable_name)
        self.stdout.write("_resolve_executable:")
        self.stdout.write(f"{result}")
        result = self._resolve_executable_updated(executable_name)
        self.stdout.write("_resolve_executable_updated:")
        self.stdout.write(f"{result}")
        self.stdout.write(f"{self.help} - Complete")

On my Windows server, the return value is different:

(venv) C:\kb>python manage.py 5668-dramatiq-process-stopping
_resolve_executable:
dramatiq
_resolve_executable_updated:
c:\kb\venv\Scripts\dramatiq 

I am starting Dramatiq using a Windows service (win32serviceutil.ServiceFramework) and Dramatiq will not start unless we have the full path i.e. c:\kb\venv\Scripts\dramatiq.

Sorry... I am not being much help here, but thought I would share.