rod icon indicating copy to clipboard operation
rod copied to clipboard

Clear the tabs open in browser

Open vipulsingh24 opened this issue 3 years ago • 3 comments

Rod Version: v0.107.3

How I can clear or close the non used tabs in the browser after say x minute.

Problem: I initiate a browser at the start of the program

u := launcher.New().
		UserDataDir("path").
		Headless(true).
		MustLaunch()

And whenever a request comes I open a new page inside the above launcher

page := rod.New().ControlURL(uc.launcher).MustConnect().MustPage(url)
defer page.MustClose()

But due to some reason, the page doesn't get close like the failure of method or a long wait for the page to open or any response from the page due to which the system memory starts increasing as the request keeps on coming.

Is there any way I can close this open non-required pages/tabs anyway after x minute (using cron)?

vipulsingh24 avatar Aug 01 '22 05:08 vipulsingh24

Please fix the format of your markdown:

7 MD031/blanks-around-fences Fenced code blocks should be surrounded by blank lines [Context: "```"]
7 MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
15 MD031/blanks-around-fences Fenced code blocks should be surrounded by blank lines [Context: "```"]
15 MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
24 MD012/no-multiple-blanks Multiple consecutive blank lines [Expected: 1; Actual: 2]
25 MD012/no-multiple-blanks Multiple consecutive blank lines [Expected: 1; Actual: 3]

generated by check-issue

rod-robot avatar Aug 01 '22 05:08 rod-robot

for _, p := range browser.MustPages() {
    p.MustClose()
}

ysmood avatar Aug 01 '22 06:08 ysmood

to @vipulsingh24

I do not think it is good idea to leave the processes like that, especially the problem mostly comes from the chrome remote protocol itself. Since rod is a wrapper, it will become a bit harder than you what you might expected...

However, if you insist, you may write some functions as...

For example... following pattern will call close function after some time (from the example, 10 min)

func newPage(b *rod.Browser) *rod.Page {
        // as usual
	p := b.MustPage()
        
        // launch a go-routine that will call the close func
	go func(page *rod.Page) {

                // set timer for close
	        timer := time.After(time.Minute * 10)
                // wait
		<- timer
		if err := page.Close(); err != nil {
			fmt.Printf("failed to close page: %+v\n", err.Error())
		}
	}(p)
        // use the page.
	return p
}

As you may have noticed, problem arises when you need to close your application before those waits.

I recommend use combination of context package and sync package (specifically, sync.WaitGroup.) If you use parent context to propagate cancellation... it may look something like this.

func newPage(browser *rod.Browser, parentCtx context.Context, wg *sync.WaitGroup) *rod.Page {
	p := browser.MustPage()

	go func(page *rod.Page, pCtx context.Context, pWg *sync.WaitGroup) {
                // report to parent wg that the page is closed (or tried at best)
                defer pWg.Done()

		timer := time.After(time.Minute * 10)

                // wait until either timer or parent context is closed
		select {
		case <-pCtx.Done():
		case <-timer:
			break
		}

		if err := page.Close(); err != nil {
			fmt.Printf("failed to close page: %+v\n", err.Error())
		} else {
			fmt.Printf("closed %+v\n", page.TargetID)
		}
	}(p, parentCtx, wg)

	return p
}

state303 avatar Aug 22 '22 08:08 state303