Add context support to Playwright browser initialization
Refactored Playwright initialization to ensure context propagation. Updated `NewPlayWrightBrowser` and related methods to accept `context.Context` for better cancellation and timeout handling. Improved error resilience and concurrency during browser setup.
This commit is contained in:
@@ -43,7 +43,7 @@ var Flags = BrowserFlags{
|
||||
},
|
||||
}
|
||||
|
||||
func FromCommand(_ context.Context, cmd *cli.Command) (extractor.Browser, error) {
|
||||
func FromCommand(ctx context.Context, cmd *cli.Command) (extractor.Browser, error) {
|
||||
var opts extractor.PlayWrightBrowserOptions
|
||||
|
||||
if ua := cmd.String("user-agent"); ua != "" {
|
||||
@@ -72,5 +72,5 @@ func FromCommand(_ context.Context, cmd *cli.Command) (extractor.Browser, error)
|
||||
|
||||
opts.ShowBrowser = cmd.Bool("visible")
|
||||
|
||||
return extractor.NewPlayWrightBrowser(opts)
|
||||
return extractor.NewPlayWrightBrowser(ctx, opts)
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func playwrightCookieToCookie(cookie playwright.Cookie) Cookie {
|
||||
}
|
||||
}
|
||||
|
||||
func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
func NewPlayWrightBrowser(ctx context.Context, opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
var thirtySeconds = 30 * time.Second
|
||||
opt := PlayWrightBrowserOptions{
|
||||
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0",
|
||||
@@ -131,19 +131,36 @@ func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
opt.ShowBrowser = o.ShowBrowser
|
||||
}
|
||||
|
||||
// Check if context is already done
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type browserResult struct {
|
||||
browser Browser
|
||||
err error
|
||||
}
|
||||
|
||||
// Create a channel for the result
|
||||
resultCh := make(chan browserResult, 1)
|
||||
|
||||
// Launch browser initialization in a separate goroutine
|
||||
go func() {
|
||||
pw, err := playwright.Run()
|
||||
|
||||
if err != nil {
|
||||
err = playwright.Install()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
resultCh <- browserResult{nil, err}
|
||||
return
|
||||
}
|
||||
|
||||
pw, err = playwright.Run()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
resultCh <- browserResult{nil, err}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +186,8 @@ func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, ErrInvalidBrowserSelection
|
||||
resultCh <- browserResult{nil, ErrInvalidBrowserSelection}
|
||||
return
|
||||
}
|
||||
var browser playwright.Browser
|
||||
|
||||
@@ -182,7 +200,8 @@ func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
|
||||
if err != nil {
|
||||
if opt.DontLaunchOnConnectFailure {
|
||||
return nil, err
|
||||
resultCh <- browserResult{nil, err}
|
||||
return
|
||||
}
|
||||
slog.Warn("failed to connect to playwright server, launching local browser", "err", err)
|
||||
launch = true
|
||||
@@ -194,7 +213,8 @@ func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
Headless: playwright.Bool(!opt.ShowBrowser),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
resultCh <- browserResult{nil, err}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,13 +240,15 @@ func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
ColorScheme: scheme,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
resultCh <- browserResult{nil, err}
|
||||
return
|
||||
}
|
||||
|
||||
if opt.CookieJar != nil {
|
||||
cookies, err := opt.CookieJar.GetAll()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting cookies from cookie jar: %w", err)
|
||||
resultCh <- browserResult{nil, fmt.Errorf("error getting cookies from cookie jar: %w", err)}
|
||||
return
|
||||
}
|
||||
|
||||
pwCookies := make([]playwright.OptionalCookie, len(cookies))
|
||||
@@ -238,11 +260,13 @@ func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
err = c.AddCookies(pwCookies)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error adding cookies to browser: %w", err)
|
||||
resultCh <- browserResult{nil, fmt.Errorf("error adding cookies to browser: %w", err)}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return playWrightBrowser{
|
||||
resultCh <- browserResult{
|
||||
browser: playWrightBrowser{
|
||||
pw: pw,
|
||||
browser: browser,
|
||||
userAgent: opt.UserAgent,
|
||||
@@ -250,7 +274,18 @@ func NewPlayWrightBrowser(opts ...PlayWrightBrowserOptions) (Browser, error) {
|
||||
cookieJar: opt.CookieJar,
|
||||
ctx: c,
|
||||
serverAddr: opt.PlayWrightServerAddress,
|
||||
}, nil
|
||||
},
|
||||
err: nil,
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for either context cancellation or browser initialization completion
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case result := <-resultCh:
|
||||
return result.browser, result.err
|
||||
}
|
||||
}
|
||||
|
||||
func (b playWrightBrowser) updateCookies(_ context.Context, page playwright.Page) error {
|
||||
@@ -337,7 +372,7 @@ func deferClose(cl io.Closer) {
|
||||
}
|
||||
|
||||
func Screenshot(ctx context.Context, target string, timeout time.Duration) ([]byte, error) {
|
||||
browser, err := NewPlayWrightBrowser(PlayWrightBrowserOptions{
|
||||
browser, err := NewPlayWrightBrowser(ctx, PlayWrightBrowserOptions{
|
||||
Timeout: &timeout,
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user