racetrack icon indicating copy to clipboard operation
racetrack copied to clipboard

Isolate job's requirements

Open iszulcdeepsense opened this issue 2 years ago • 8 comments

A job runs a single Python interpreter process that contains 2 codebases:

  • wrapper code (handling http, metrics, swagerUI, etc)
  • actual job's logic

Each of them have its third-party dependencies installed with pip install -r requirements.txt. That raises a risk of conflicting packages. Although they are installed in 2 different virtual environments, they're still running in the same single Python process that makes it impossible to load 2 different versions of the same package at the same time. For instance, if wrapper code relies on fastapi==0.100.0, but the job depends on fastapi==0.90.0, there might be the clash, cause the wrapper's library takes precedence when loading modules in Python and the job will use fastapi==0.90.0

I see the only good way out of here: Wrapper code shouldn't have any third-party dependency (that could be overwritten or conflicted by a job). Then, there won't be any conflict. It can either implement the necessary logic on its own or use "forked" versions of libraries (eg. FastAPI renamed to fastapi_racetrack package).

This task has a low priority as it rarely happens to break something (but when it does, it's astonishing and hard to find).

iszulcdeepsense avatar Jul 14 '23 14:07 iszulcdeepsense

This issue popped up with Pydantic (ours is ==2.6.1 atm) and a certain Walking Cat (theirs is not 2.6.1) when using the Dockerfile jobtype, so we might want to look into vendoring Pydantic.

anders314159 avatar Jul 01 '24 11:07 anders314159

Speaking of "vendoring", that might be a good workaround. What we really need is to create a copy of pydantic package with all imports updated so that it can be imported with from pydantic_vendored import ... apart from catwalk's pydantic module. Do you know a tool for doing this?

iszulcdeepsense avatar Jul 08 '24 09:07 iszulcdeepsense

The more I read and think about vendoring, the less I like it. We are taking on the responsibilities of maintaining our vendored package with all that entails.

I'd rather look for a way to isolate Catwalk from racetrack when using the Dockerfile Job Type.

anders314159 avatar Jul 12 '24 07:07 anders314159

Wrapper code shouldn't have any third-party dependency

Difficult but clean.

a certain Walking Cat

Why is Catwalk being developed as a RT job?

look into vendoring Pydantic

Why? Are you thinking of having different versions of pydantic, one for RT and one for the job, and then loading the RT one from a different location?


Concerning vendoring: it's either bad nor good, it's situational. It doesn't feel good in Python because of python's tooling which is at this stage not very modern. In golang for example, vendoring is clean and efficient, and supported in the first-party toolchain. go mod vendor -u should tell you all you need to know.

I'm not sure we should accommodate concurrent different versions of the same library in a jobtype. In the ideal scenario, there's no third party dependencies in the job type plugin. Otherwise, if someone wants to use a library the jobtype uses, the docs should be clear they can only use the version shipped with the jobtype, and maybe even the builder should error out if the user has requested a library shipped in the jobtype. So a good way to accomplish this is like Irek's first thought, to remove third party dependencies.

My concern is, there's many people who have looked into doing this with Python over the last couple of decades, and no one has a good solution. The best I've seen is having 2 versions installed, but not having 2 versions active in the same running interpreter process. I just think if we try to do this we'll end up with all sorts of really nasty errors to troubleshoot because we're doing something Python is not designed for, and thinking we're more clever than so many other people.

And speaking of jobtypes, isn't this an issue for the Python jobtype, not for core RT?

JosefAssadERST avatar Jul 29 '24 07:07 JosefAssadERST

Why is Catwalk being developed as a RT job?

It's a bit different. Their RT job requires Catwalk as one of dependencies in requirements list. To sum up: Wrapper code (which uses pydantic) imports a job, a job may import Catwalk, which in turn imports a different version of pydantic. That's where the conflict comes from.

Why? Are you thinking of having different versions of pydantic, one for RT and one for the job, and then loading the RT one from a different location?

Yes, that's exactly why.

iszulcdeepsense avatar Jul 29 '24 08:07 iszulcdeepsense

Their RT job requires Catwalk as one of dependencies in requirements list

Ah, Catwalk client. Got it.

Still feels like your initial thought ot removing third party dependencies from the job type is the most viable option. Actually should be a strong recommendation for job type developers.

JosefAssadERST avatar Jul 29 '24 08:07 JosefAssadERST

And speaking of jobtypes, isn't this an issue for the Python jobtype, not for core RT?

You're right, this issue originated from Racetrack back in the days, but at this moment it's more related to https://github.com/TheRacetrack/job-runner-python-lib

When I look at its code it has a few occurences of pydantic usage. This library originated from a racetrack client and now it's a small subset of Racetrack's codebase. I suppose it should be fairly easy to replace pydantic with something built-in (like dataclasses). That would start a process of removing third-party dependencies from job-runner-python-lib. It also means that its codebase would start its own life (not longer being shared with Racetrack core).

iszulcdeepsense avatar Jul 29 '24 08:07 iszulcdeepsense

This is a general discussion, so I've made a separate issue for pydantic removal: https://github.com/TheRacetrack/job-runner-python-lib/issues/3

iszulcdeepsense avatar Jul 29 '24 08:07 iszulcdeepsense