inventree / InvenTree

Open Source Inventory Management System
https://docs.inventree.org
MIT License
4.19k stars 754 forks source link

Issue loading custom plug-in with worker #7489

Open mp-strachan opened 3 months ago

mp-strachan commented 3 months ago

Please verify that this bug has NOT been raised before.

Describe the bug*

I have made a custom build of matmair's WLED Locator (as the one from the git repo no longer functions).

If I load my version of the plugin (from local file using INVENTREE_PLUGIN_DIR) without running a worker (docker), then the plug-in works perfectly fine. As soon as I run it on a stack with a worker container, I get the error:

Can't pickle <class 'plugins.wled.WledPlugin.WledPlugin'>: it's not the same object as plugins.wled.WledPlugin.WledPlugin when trying to execute an action.

INVENTREE_PLUGIN_DIR is a mapped volume in my docker-composer, and is configured for both the server and worker container.

Once this (loading with a worker enabled) has occurred once, I must completely remove the plugin config from django admin, remove the pycache directory from plug-in directory and restart the server (without a worker), else the issue persists.

Steps to Reproduce

  1. Setup docker-compose with a server but no worker
  2. Copy plugin files to plugin directory
  3. Map plugin directory to container volume directory
  4. Configure INVENTREE_PLUGIN_DIR env value to point to plugin directory
  5. Start docker stack & configure plugin. Everything works.
  6. Stop docker stack, add worker to docker-compose (inc. volume map for plug-in)
  7. Start docker stack. Plugin now errors.

Docker-compose.yml excerpt (excluding cache, proxy & DB)

  inventree-server:
    image: inventree/inventree:${INVENTREE_TAG:-stable}
    depends_on:
      - inventree-db
    env_file:
      - .env
    volumes:
      - ./data/server:/home/inventree/data
      - ./data/plugins:/home/inventree/plugins
    restart: unless-stopped
    networks:
      - private

  inventree-worker:
    image: inventree/inventree:${INVENTREE_TAG:-stable}
    command: invoke worker
    depends_on:
      - inventree-server
    env_file:
      - .env
    volumes:
      - ./data/server:/home/inventree/data
      - ./data/plugins:/home/inventree/plugins
    restart: unless-stopped
    networks:
      - private

.env excerpt:

INVENTREE_TAG=latest
...
INVENTREE_PLUGINS_ENABLED=True
INVENTREE_PLUGIN_DIR=/home/inventree/plugins

Expected behaviour

Plugin should work with both standalone server and with server + worker.

Deployment Method

Version Information

Using latest tag for both worker & server

Please verify if you can reproduce this bug on the demo site.

Relevant log output

Traceback (most recent call last):

File "/home/inventree/src/backend/InvenTree/InvenTree/tasks.py", line 204, in offload_task
task.run()

File "/root/.local/lib/python3.11/site-packages/django_q/tasks.py", line 727, in run
self.id = async_task(self.func, *self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "/root/.local/lib/python3.11/site-packages/django_q/tasks.py", line 70, in async_task
pack = SignedPackage.dumps(task)
^^^^^^^^^^^^^^^^^^^^^^^^^

File "/root/.local/lib/python3.11/site-packages/django_q/signing.py", line 15, in dumps
return signing.dumps(
^^^^^^^^^^^^^^

File "/root/.local/lib/python3.11/site-packages/django/core/signing.py", line 152, in dumps
return TimestampSigner(key=key, salt=salt).sign_object(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "/root/.local/lib/python3.11/site-packages/django/core/signing.py", line 250, in sign_object
data = serializer().dumps(obj)
^^^^^^^^^^^^^^^^^^^^^^^

File "/root/.local/lib/python3.11/site-packages/django_q/signing.py", line 35, in dumps
return pickle.dumps(obj, protocol=pickle.HIGHEST_PROTOCOL)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

_pickle.PicklingError: Can't pickle <class 'plugins.wled.WledPlugin.WledPlugin'>: it's not the same object as plugins.wled.WledPlugin.WledPlugin

---

inventree-server_1  | WARNING: '<bound method PluginsRegistry.call_plugin_function of <plugin.registry.PluginsRegistry object at 0x7fdbbdd31710>>' not offloaded due to Can't pickle <class 'plugins.wled.WledPlugin.WledPlugin'>: it's not the same object as plugins.wled.WledPlugin.WledPlugin
inventree-server_1  | Can't pickle <class 'plugins.wled.WledPlugin.WledPlugin'>: it's not the same object as plugins.wled.WledPlugin.WledPlugin
philipp2310 commented 2 months ago

quick fix, and dirty:

I locally modified

/opt/inventree/src/backend/InvenTree/plugin/base/locate/api.py

in lines 63 and 81 to include

force_sync=True

Surely not the perfect solution (even if done centrally by InvenTree) as locating should be done asynchronously, but it works for now

github-actions[bot] commented 2 weeks ago

This issue seems stale. Please react to show this is still important.

wolflu05 commented 2 weeks ago

Still not fixed