playwright-community / playwright-go

Playwright for Go a browser automation library to control Chromium, Firefox and WebKit with a single API.
https://playwright-community.github.io/playwright-go/
MIT License
2.25k stars 163 forks source link

[Bug]: [chrome] <defunct> left behind #490

Open morten-holm opened 2 months ago

morten-holm commented 2 months ago

Environments

Bug description The provided example leaves behind a defunct chromium process.

To Reproduce This code reproduces the problem:

package main

import (
    "fmt"
    "net/http"

    "github.com/playwright-community/playwright-go"
)

func pingHandler(w http.ResponseWriter, r *http.Request) {
    pw, err := playwright.Run()
    if err != nil {
        panic(err)
    }
    defer func() {
        err = pw.Stop()
        if err != nil {
            panic(err)
        }
    }()

    browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
        Args: []string{
            "--allow-running-insecure-content",
        },
        Headless: playwright.Bool(true),
    })
    if err != nil {
        panic(err)
    }
    defer func() {
        err = browser.Close()
        if err != nil {
            panic(err)
        }
    }()

    baseUrl := "https://playwright.dev/"
    permissions := []string{"clipboard-read", "clipboard-write", "storage-access"}

    page, err := browser.NewPage(playwright.BrowserNewPageOptions{
        BaseURL:           playwright.String(baseUrl),
        BypassCSP:         playwright.Bool(true),
        JavaScriptEnabled: playwright.Bool(true),
        Permissions:       permissions,
        Viewport: &playwright.Size{
            Width:  1240,
            Height: 800,
        },
    })
    if err != nil {
        panic(err)
    }
    defer func() {
        err = page.Close()
        if err != nil {
            panic(err)
        }
    }()

    webErrors := make([]string, 0)

    page.OnPageError(func(e error) {
        webErrors = append(webErrors, e.Error())
    })

    page.OnConsole(func(e playwright.ConsoleMessage) {
        webErrors = append(webErrors, e.Text())
    })

    _, err = page.Goto(baseUrl, playwright.PageGotoOptions{
        WaitUntil: playwright.WaitUntilStateNetworkidle,
    })
    if err != nil {
        panic(err)
    }

    for _, webError := range webErrors {
        fmt.Printf("%s\n", webError)
    }

    _, err = fmt.Fprintf(w, "pong")
    if err != nil {
        panic(err)
    }
}

func main() {
    err := playwright.Install(&playwright.RunOptions{
        Browsers: []string{"chromium"},
    })

    if err != nil {
        panic(err)
    }

    http.HandleFunc("/ping", pingHandler)

    fmt.Println("Starting server at :8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        fmt.Printf("Error starting server: %s\n", err)
    }
}
$ git clone https://github.com/morten-holm/playwright-demo.git
$ docker build -t playwright-demo .
$ docker run --rm -p 8080:8080 playwright-demo
$ http localhost:8080/ping

After this running 'ps xua' will give a result like this:

# ps xua | grep chrome
root       128  0.0  0.0      0     0 ?        Z    06:16   0:00 [chrome] <defunct>
root       129  0.0  0.0      0     0 ?        Z    06:16   0:00 [chrome] <defunct>
root       198  0.0  0.0   3124  1384 pts/0    S+   06:16   0:00 grep chrome
canstand commented 2 months ago

You just need to start a browser and close it when the program exits. Just create a new BrowserContext for each request.