Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attach - preLaunchTask not working as expected #3439

Closed
adibradfield opened this issue Feb 18, 2022 · 13 comments
Closed

Attach - preLaunchTask not working as expected #3439

adibradfield opened this issue Feb 18, 2022 · 13 comments

Comments

@adibradfield
Copy link

This is basically a duplicate of #3304 that got closed because the original reporter didn't provide extra information.

I am currently having the same issue where I am not able to setup my launch configurations in a way that I can do a docker-compose up before debugging, and a docker-compose down once I've finished debugging

The issue seems to be that the debugger tries attaching to the container before running the prelaunch task

This is what my launch configuration looks like:

{
        "name": "Docker .NET Core Attach (Preview)",
        "type": "docker",
        "request": "attach",
        "platform": "netCore",
        "sourceFileMap": {
            "/src": "${workspaceFolder}/Integrations.Equifinance"
        },
        "containerName": "fmg-equifinance-debug",
        "preLaunchTask": "compose-up-dev",
        "postDebugTask": "compose-stop-dev"
}

Then I have my tasks:

{
      "type": "shell",
      "label": "compose-up-dev",
      "options": {
          "cwd": "${workspaceFolder}/../../"
      },
      "command": "docker-compose -f compose.yml -f fmg-integrations-lenders/Integrations.Equifinance/Integrations.Equifinance/compose.debug.yml up -d --build fmg-equifinance",
      "presentation": {
          "reveal": "always",
          "panel": "shared"
      },
      "problemMatcher": "$msCompile"
  },
  {
      "type": "shell",
      "label": "compose-stop-dev",
      "options": {
          "cwd": "${workspaceFolder}/../../"
      },
      "command": "docker-compose stop",
      "presentation": {
          "reveal": "always",
          "panel": "shared"
      }
  }

I have tried the suggestion from the other issue to use the actual docker compose tasks, but I get the same result.

I get the following output:

Error: Process 'docker exec -i "fmg-equifinance-debug" /bin/sh -c ...' exited with code 1
Error: Error response from daemon: Container a3705d5646c857749b8ba370851a80ffb9a1ec416b1c2a51ff3f920bf28591da is not running

If I remove the containerName property from the launch configuration I instead get this error:

Error: No running containers are available to attach.

For now, to get around the issue I am running the compose-up-dev task from the command palette and then launching the debug session, and that works. This indicates to me that the likely cause is that the "preLaunchTask" is getting called at the wrong time

@bwateratmsft
Copy link
Collaborator

I'll take a look and see if there's a way to do this.

Unfortunately we have no control over when preLaunchTask gets called; VSCode structured debugging in a weird way--first, debug resolves, then the preLaunchTask runs, then debug executes. It's a pain for us because we have to know the container name to attach to (and a whole lot of other info) at the time of debug resolving...before the container is even running.

I think what may be happening when containerName is present is the compose call returns before the container is fully running; when containerName is absent it has to ask for the container to attach to (at the time of resolving), but it hasn't been started yet so you see that "No running containers" message.

@adibradfield
Copy link
Author

So I've had a read through the code myself to try and get a bit more of an understanding of how all this works. By the looks of it (I haven't done any debugging) the errors are probably getting thrown during the check to see if the debugger needs to be installed into the container when resolving the configuration.

I wonder whether a solution to this might be to override the preLaunchTask that gets resolved with another task that first runs the original preLaunchTask (or a task provided by a new docker specific field?) and only once that's completed try and install the debugger, rather than trying to do it during the resolve?

@dbreshears dbreshears added this to the 1.21.0 milestone Feb 22, 2022
@Lukas-J
Copy link

Lukas-J commented Feb 27, 2022

Hi there,
I've got a similar problem: Clicking on the play button in "RUN AND DEBUG" for "Python: Remote Attach", docker-compose get's executed but the debugger does not get entered. Clicking it directly again, executes docker-compose again and then starts the debugging mode (the botom line turns orange).

Another workaround is the described way in https://code.visualstudio.com/docs/containers/docker-compose#_python. Left click on docker-compose.dev.yml -> "Compose UP" and then clicking the play button in "RUN AND DEBUG" for "Python: Remote Attach".

I hope, you can fix this issue. Below, you find my tasks.json, launch.json, Dockerfile and docker-compose.dev.yml.

Cheers!


tasks.json:

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Run docker-compose up",
      "type": "docker-compose",
      "dockerCompose": {
        "up": {
          "detached": true,
          "build": true,
        },
        "files": [
          "${workspaceFolder}/docker-compose.dev.yml"
        ]
      }
    }
  ]
}

launch.json:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Remote Attach",
            "type": "python",
            "request": "attach",
            "port": 5678,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/app"
                }
            ],
            "preLaunchTask": "Run docker-compose up",
            "serverReadyAction": {
                "action": "openExternally",
                "pattern": "listening on port ([0-9]+)",
                "uriFormat": "http://localhost:%s",
                "webRoot": "${workspaceFolder}"
            }
        },
    ]
}

Dockerfile:

# syntax=docker/dockerfile:1

# see https://docs.docker.com/language/python/build-images/

FROM python:3

# Force the stdout and stderr streams to be unbuffered. This option has no effect on the stdin stream.
ENV PYTHONUNBUFFERED=1

# If this is set to a non-empty string, Python won’t try to write .pyc files on the import of source modules.
ENV PYTHONDONTWRITEBYTECODE=1

WORKDIR /app

COPY requirements.txt requirements.txt

RUN pip3 install -r requirements.txt

COPY . .

# Set locale
RUN apt update
RUN apt install -y locales
RUN sed -i '/de_DE.UTF-8/s/^# //g' /etc/locale.gen
RUN locale-gen

# TODO Add new user
# RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
# USER appuser

CMD ["python", "./server.py"]

docker-compose.dev.yml

version: '3.8'

services:
  web:
    build:
      context: .
    command:
      [
        "sh",
        "-c",
        "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 server.py runserver 0.0.0.0:5000 --nothreading --noreload"
      ] # For debugging only
    depends_on:
      - db
    ports:
      - 5000:5000
      - 5678:5678 # For debugging only
    restart: always
    volumes:
      - ./:/app

  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: example
    expose:
      - "5432"
    # ports:
    #   - 5432:5432
    restart: always
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - postgres_config:/etc/postgresql

volumes:
  postgres_data:
  postgres_config:

@bwateratmsft
Copy link
Collaborator

So I've had a read through the code myself to try and get a bit more of an understanding of how all this works. By the looks of it (I haven't done any debugging) the errors are probably getting thrown during the check to see if the debugger needs to be installed into the container when resolving the configuration.

I wonder whether a solution to this might be to override the preLaunchTask that gets resolved with another task that first runs the original preLaunchTask (or a task provided by a new docker specific field?) and only once that's completed try and install the debugger, rather than trying to do it during the resolve?

I think you're right @adibradfield; the debugger check is happening during the debug config resolve phase (which is before the containers are started). If you set the following netCore.debuggerPath option in launch.json, does it work? Your compose-up-dev task--in whichever compose file(s) it uses to launch the app--will need to map the debugger in from ~/.vsdbg to /remote_debugger; our docker-compose.debug.yml file created by scaffolding does this. Example below.

        {
            "name": "Docker .NET Core Attach (Preview)",
            "type": "docker",
            "request": "attach",
            "platform": "netCore",
            "sourceFileMap": {
                "/src": "${workspaceFolder}/Integrations.Equifinance"
            },
            "containerName": "fmg-equifinance-debug",
            "preLaunchTask": "compose-up-dev",
            "postDebugTask": "compose-stop-dev",
            "netCore": {
                "debuggerPath": "/remote_debugger/vsdbg" // Add this `netCore.debuggerPath` option, with this value
            }
        },

Setting this value bypasses the debugger check.

Sample compose document with the debugger mapping:

# Please refer https://aka.ms/HTTPSinContainer on how to setup an https developer certificate for your ASP .NET Core service.

version: '3.4'

services:
  net6app:
    image: net6app
    build:
      context: .
      dockerfile: ./Dockerfile
    ports:
      - 5287:5287
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    volumes:
      - ~/.vsdbg:/remote_debugger:rw # This is what maps in the debugger

If the debugger is not yet installed on your local machine, running the "Docker .NET Core Attach (Preview)" launch configuration once without the debuggerPath option should initiate the installation.

@bwateratmsft
Copy link
Collaborator

bwateratmsft commented Mar 3, 2022

@Lukas-J for your Python app--I've seen similar issues, where the first run starts the app but no debugger is launched, and then the second attempt does start debugging. It has something to do with the somewhat complicated way that debugging is initiated in Python apps. I'm guessing that the container is started, with debugpy being installed and then starting, but before that happens the Python debugger tries to attach.

@int19h is there a way to set up retries / a timeout on the Python attach config?

@Lukas-J tasks can depend on other tasks, so one possible option would be to have the preLaunchTask that does a brief sleep--maybe 5 seconds or something like that--which itself dependsOn the actual compose up task. So the procedure would be compose up, sleep 5 seconds, then execute the Python attach config.

@int19h
Copy link

int19h commented Mar 3, 2022

There is a timeout in debugpy, but it's not configurable, and the exact value depends on which stage it gets stuck on.

For "attach" logic in vscode-python, it relies on VSCode's own builtin support for DAP over TCP, so whatever timeout / retry functionality is available should be applicable - but I don't recall there being any last time I checked. @paulacamargo25 might have more up-to-date knowledge on this.

@bwateratmsft
Copy link
Collaborator

bwateratmsft commented Mar 3, 2022

If the stuck stage is in waiting for debugpy (in the container) to start with the app, in order to attach, what is that timeout?

We install and launch debugpy at container startup like this: pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 server.py runserver 0.0.0.0:5000 --nothreading --noreload.

Obviously depending on connection it could take a long time to download and install debugpy...

@int19h
Copy link

int19h commented Mar 4, 2022

For "attach", the VSCode side is not aware of debugpy lifecycle when connecting - it (or rather VSCode itself, since the extension just returns the host/port to connect to) simply connects to the specified address. For that one, the timeout is also determined by VSCode. If I remember correctly, it was somewhere on the order of 1 minute.

@Lukas-J
Copy link

Lukas-J commented Mar 8, 2022

sleep 2 fixes the problem for me

tasks.json:

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Run docker-compose up",
      "type": "docker-compose",
      "dockerCompose": {
        "up": {
          "detached": true,
          "build": true,
        },
        "files": [
          "${workspaceFolder}/docker-compose.dev.yml"
        ]
      }
    },
    {
      "label": "sleep",
      "type": "shell",
      "command": "sleep 2",
      "dependsOn": "Run docker-compose up",
    }
  ]
}

launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Remote Attach",
            "type": "python",
            "request": "attach",
            "port": 5678,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/app"
                }
            ],
            "preLaunchTask": "sleep",
            "serverReadyAction": {
                "action": "openExternally",
                "pattern": "listening on port ([0-9]+)",
                "uriFormat": "http://localhost:%s",
                "webRoot": "${workspaceFolder}"
            }
        },
    ]
}

@bwateratmsft
Copy link
Collaborator

RE: the Python issue; I did some poking around in VSCode's debug adapter client code. It doesn't appear to accept any options. I'm guessing that since debugpy isn't ready yet by the time the connection is trying to start, the connection request is rejected outright; so timeouts wouldn't apply anyway. I don't think there's really anything that we can do about this other than the recommended injection of a sleep task. VSCode could provide some options for retry/timeouts but that would be outside our scope.

RE: the .NET issue; I think the ultimate solution is pretty much #2289. We can't verify/copy the debugger before the container is running, but the resolveDebugConfiguration call happens before any pre-launch tasks. The only solution is to move to resolveDebugConfigurationWithSubstitutedVariables, which happens after all pre-launch tasks. I am going to reopen that issue, and dupe this one to that one.

The simplest workaround is to manually run the compose up task/script/etc. before doing the Docker .NET attach, but of course this is an inconvenience. The only possible workaround for that is therefore to use the debuggerPath setting to bypass the debug check logic, along with mapping in the debugger directories.

@Lukas-J
Copy link

Lukas-J commented Mar 8, 2022

Hi again,
before this issue gets closed for good, someone should add the thing with the sleep task to the documentation, e.g. in https://code.visualstudio.com/docs/containers/docker-compose#_python.

@bwateratmsft
Copy link
Collaborator

I don't want the docs to get too far into the weeds...what do you think @ucheNkadiCode? Should we add docs or just let users discover this issue?

@ucheNkadiCode
Copy link
Contributor

ucheNkadiCode commented Mar 14, 2022

@bwateratmsft this is something that has been mentioned enough that I wouldn't mind adding it to tips and tricks. Does this only exist in the world of python? Or .NET and other languages have this issue with prelaunch tasks?

@microsoft microsoft locked and limited conversation to collaborators Apr 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants