import os
import asyncio
import logging
from multiprocessing import cpu_count

from async_timeout import timeout

from .chromerdp import ChromeRemoteDebugger

logger = logging.getLogger(__name__)

PRERENDER_TIMEOUT = int(os.environ.get('PRERENDER_TIMEOUT', 30))
CONCURRENCY_PER_WORKER = int(os.environ.get('CONCURRENCY', cpu_count() * 2))
MAX_ITERATIONS = int(os.environ.get('ITERATIONS', 200))


class Prerender:
    def __init__(self, host='localhost', port=9222, loop=None):
        self.host = host
        self.port = port
        self.loop = loop
        self._rdp = ChromeRemoteDebugger(host, port, loop=loop)
        self._ctrl_tab = None
        self._idle_tabs = asyncio.Queue(loop=self.loop)

    async def connect(self):
        tabs = await self._rdp.debuggable_tabs()
        self._ctrl_tab = tabs[0]
        await self._ctrl_tab.attach()
        logger.info('Connected to control tab %s', self._ctrl_tab.id)
        for i in range(CONCURRENCY_PER_WORKER):
            tab = await self._rdp.new_tab()
            await self._idle_tabs.put(tab)

    async def tabs(self):
        return await self._rdp.tabs()

    async def version(self):
        return await self._rdp.version()

    async def new_tab(self, url=None):
        await self._ctrl_tab.send({
            'method': 'Target.createTarget',
            'params': {
                'url': url or 'about:blank'
            }
        })
        res = await self._ctrl_tab.recv()
        tab_id = res['result']['targetId']
        logger.info('Created new tab %s', tab_id)
        tabs = await self._rdp.debuggable_tabs()
        tab = [tb for tb in tabs if tb.id == tab_id][0]
        return tab

    async def close_tab(self, tab_id):
        await self._ctrl_tab.send({
            'method': 'Target.closeTarget',
            'params': {'targetId': tab_id}
        })
        res = await self._ctrl_tab.recv()
        logger.info('Closed tab %s', tab_id)
        return res

    async def shutdown(self):
        tabs = await self._rdp.debuggable_tabs()
        for tab in tabs:
            await self.close_tab(tab.id)
        await self._ctrl_tab.dettach()

    async def render(self, url):
        tab = await self._idle_tabs.get()
        try:
            await tab.attach()
            await tab.listen()
            await tab.navigate(url)
            with timeout(PRERENDER_TIMEOUT):
                html = await tab.wait()
            await tab.navigate('about:blank')
        finally:
            if tab.websocket:
                await tab.dettach()
            self._idle_tabs.task_done()
            await self.manage_tab(tab)
        return html

    async def manage_tab(self, tab):
        if tab.iteration < MAX_ITERATIONS:
            await self._idle_tabs.put(tab)
            return

        await self.close_tab(tab.id)
        tab = await self._rdp.new_tab()
        await asyncio.sleep(0.5)
        await self._idle_tabs.put(tab)
        logger.info('New tab %s added', tab.id)

@@ -614,38 +614,8 @@
 op)%0A
-        self._ctrl_tab = None%0A
     
@@ -670,227 +670,64 @@
 op)%0A
-%0A
     
-async def connect(self):%0A        tabs = await self._rdp.debuggable_tabs()%0A        self._ctrl_tab = tabs%5B0%5D%0A        await self._ctrl_tab.attach()%0A        logger.info('Connected to control tab %25s', self._ctrl_tab.id)
+    self._tab_ids = %5B%5D%0A%0A    async def connect(self):
 %0A   
@@ -857,16 +857,57 @@
 put(tab)
+%0A            self._tab_ids.append(tab.id)
 %0A%0A    as
@@ -1054,873 +1054,88 @@
 def 
-new_tab(self, url=None):%0A        await self._ctrl_tab.send(%7B%0A            'method': 'Target.createTarget',%0A            'params': %7B%0A                'url': url or 'about:blank'%0A            %7D%0A        %7D)%0A        res = await self._ctrl_tab.recv()%0A        tab_id = res%5B'result'%5D%5B'targetId'%5D%0A        logger.info('Created new tab %25s', tab_id)%0A        tabs = await self._rdp.debuggable_tabs()%0A        tab = %5Btb for tb in tabs if tb.id == tab_id%5D%5B0%5D%0A        return tab%0A%0A    async def close_tab(self, tab_id):%0A        await self._ctrl_tab.send(%7B%0A            'method': 'Target.closeTarget',%0A            'params': %7B'targetId': tab_id%7D%0A        %7D)%0A        res = await self._ctrl_tab.recv()%0A        logger.info('Closed tab %25s', tab_id)%0A        return res%0A%0A    async def shutdown(self):%0A        tabs = await self._rdp.debuggable_tabs()%0A        for tab in tabs:%0A            await self
+shutdown(self):%0A        for tab_id in self._tab_ids:%0A            await self._rdp
 .clo
@@ -1148,51 +1148,12 @@
 (tab
-.
+_
 id)
-%0A        await self._ctrl_tab.dettach()
 %0A%0A  
@@ -1811,22 +1811,48 @@
 ait 
-self
+tab
 .close
-_tab
+()%0A        self._tab_ids.remove
 (tab
@@ -1960,32 +1960,69 @@
 e_tabs.put(tab)%0A
+        self._tab_ids.append(tab.id)%0A
         logger.i

Use json/close API to close tab