Hey Flyte community! I have a problem with propaga...
# flyte-support
h
Hey Flyte community! I have a problem with propagating
FlyteUserException
raised in
ContainerTask
back to Flyte workflow. I have no problem propagating
FlyteUserException
from decorated tasks (
@task
) though. Details in 🧵
👀 1
Decorated tasks (
@task
) : • Flyte-workflow ↔️ Python-Task ◦ raising
FlyteUserException
in
Python-Task
correctly propagates the exception to workflow. Raw-Containers (
ContainerTask
): • Flyte-workflow ↔️ Raw-Container(ContainerTask) ◦ raising
FlyteUserException
in
Raw-Container
does not propagate the exception to workflow. ◦ the logs do have exceptions raised though. In
ContainerTask
, it only results in a non-zero exit code returned by container. The nuance of python exception
FlyteUserException
is lost between the container and task running the container - which is not surprising as Docker containers are not expected to propagate Python exceptions. So to get around this limitation, we were thinking of then inspecting the logs of container and then raise the same
FlyteUserException
again to be caught by Workflow. For that, we overrode ContainerTask.execute() [link] based on documentation. But what we observed is the overridden method
execute
is not invoked at all. Questions: • for our use case of passing on
FlyteUserException
from a
ContainerTask
to a workflow , do you think overriding
execute
is the way to go? Or is there a better approach? • if overriding
execute
is a good approach, why is our code not working? I have a sample code below that captures what we are attempting.
Copy code
class CustomContainerTask(ContainerTask):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def execute(self, **kwargs) -> LiteralMap:
        client = docker.from_env()
        container = client.containers.run(self.image, self.command)
        if "FlyteUserException" in container:
            raise FlyteException("Exception in execute()")
        return container
h
@hallowed-wall-36631, before we start diving into the container task intricacies, can we take a step back and talk about why you are trying to run flytekit in a container task? For example, why can't you use a regular
@task
?
h
We have a project where we are better off running dbt projects as a Raw Container. The main reason is we need to use thin Python wrapper scripts to run dbt. These scripts does a variety of stuff like accept custom arguments, specialized logs handlers etc. Long story short, we need to run dbt as a Container. We are very familiar with using decorated tasks in many other contexts. But for dbt, we realize RawContainers lets us do many things which would have been hard (not impossible especially with recent dbt’s Python API) otherwise. Hope that gives you enough context.
h
Got it. First a bit of context around
FlyteUserException
and its use inside
flytekit
. In order to run user code,
flytekit
follows an implicit protocol under the covers. If you read this code in entrypoint.py you'll notice that we encode the outputs of a task into a
LiteralMap
protobuf message and write it to a specific location, this is also where exceptions are handled, we write a special protobuf file called
error.pb
and encode the exception in it. Unfortunately, the current implementation of raw containers (which are handled by flytecopilot) doesn't follow that protocol to handle errors. This would be a wonderful extension to raw containers and I'd be more than happy to collaborate on a PR. That said, have you explored Shell Tasks? Error handling in those is not great either, but they might unblock your use-case quicker.
h
@high-accountant-32689 Thanks for that explanation! So that would explain on how errors/exceptions are not passed to Flyte from a RawContainer. So its for this limitation, we were exploring the possibility of overriding ContainerTask method execute. I was hoping that that atleast I would able to inspect the logs from container execution, and then raise the exception again. So the question boils down to - is there a mechanism to inspect container-logs that would enable us write code like raising exceptions? ShellTasks won’t work in this use case as we already are very invested in RawContainers. And RawContainers have worked really well for us. This exception handling is the first time we hit a roadblock.
Or a better question about writing out
LiteralMap
- isn’t that whats already done in ContainerTask method execute?
h
Sorry for the confusion. The
execute
in
ContainerTask
is only invoked during local executions (I'll make a note to clarify that in either the docstring of in the actual method definition). The way the literal map is composed in the case of remote invocations of of raw containers is handled in https://github.com/flyteorg/flyte/blob/025296a61105bdb8f7932a7f15af8cd0aefc4a5e/flytecopilot/data/upload.go#L117-L191. Notice how we go from local files written by the container to a single
LiteralMap
object that's written to the meta bucket. In other words, the protocol followed by raw containers at runtime does not involve flytekit at all. We assume that the user code is going to write (protobuf) files to the output dir and the flytecopilot sidecar turns those into a single output
LiteralMap
after the container finishes.
That said, we can augment this mechanism to handle user-provided errors in raw containers (by modifying flytecopilot). It's just that this was not implemented yet.
h
(apologies for the late reply) Got it! Thanks for the explanation. I wish I knew enough Go to make a contribution. Something for the near future!