2

I am using this asynchronous project (called Broker - see git) with the following code:

   proxies = asyncio.Queue()
   broker = Broker(proxies)
   tasks = asyncio.gather(broker.find(types = ['HTTPS'], strict = True, limit = 10),
                               self.storeProxies(proxies))
   loop = asyncio.get_event_loop()
   loop.run_until_complete(tasks)

where self.storeProxies is an async function that contains

while True:
    proxy = await proxies.get()
    if proxy is None: break
    self.proxies['http://{0}:{1}'.format(proxy.host, proxy.port)] = 1

However, I do not think that it is related to the Broker part (not sure of course).

Everytime I run this code, after a quite random number of successes, it fails with [WinError 10038] An operation was attempted on something that is not a socket. I then tried to do some research and ended up at this answer. But when trying with this code, I get this error:

ValueError: loop argument must agree with Future

Any ideas on how to deal with this?

Details that might be useful:

OS: Windows 10 (version 1809) Python version: 3.7.1

Based on the answer from Mikhail Gerasimov

async def storeProxies(self, proxies):
    logger.info("IN IT!")
    while True:
        proxy = await proxies.get()
        if proxy is None: break
        self.proxies['http://{0}:{1}'.format(proxy.host, proxy.port)] = 1

async def getfetching(self, amount):
    from proxybroker import Broker

    proxies = asyncio.Queue()
    broker = Broker(proxies)
    return await asyncio.gather(
        broker.find(
            types = ['HTTP', 'HTTPS'],
            strict = True,
            limit = 10
        ),
        self.storeProxies(proxies)
    )
def fetchProxies(self, amount):
    if os.name == 'nt':
        loop = asyncio.SelectorEventLoop() # for subprocess' pipes on Windows
        asyncio.set_event_loop(loop)
    else:
        loop = asyncio.get_event_loop()
    loop.run_until_complete(self.getfetching(amount))
    logger.info("FETCHING COMPLETE!!!!!!")
    logger.info('Proxies: {}'.format(self.proxies))

where fetchProxies is called at certain intervals from another place. This works perfectly the first time, but then "fails" with the warnings:

2019-04-06 21:04:21 [py.warnings] WARNING: d:\users\me\anaconda3\lib\site-packages\proxybroker\providers.py:78: DeprecationWarning: The object should be created from async function
  headers=get_headers(), cookies=self._cookies, loop=self._loop

2019-04-06 21:04:21 [py.warnings] WARNING: d:\users\me\anaconda3\lib\site-packages\aiohttp\connector.py:730: DeprecationWarning: The object should be created from async function
  loop=loop)

2019-04-06 21:04:21 [py.warnings] WARNING: d:\users\me\anaconda3\lib\site-packages\aiohttp\cookiejar.py:55: DeprecationWarning: The object should be created from async function
  super().__init__(loop=loop)

followed by a behavior that seems like an infinite loop (hard stuck outputting nothing). Noteworthy, this also happened to me in the example from Gerasimov (in the comments) when importing Broker globally. Finally, I am starting to see the light of the tunnel.

1 Answers1

0

Take a look at this part:

proxies = asyncio.Queue()

# ...

loop.run_until_complete(tasks)

asyncio.Queue() when created is bound to current event loop (default event loop or one been set to current with asyncio.set_event_loop()). Usually only loop object is bound to can manage it. If you change current loop, you should recreate object. Same is true for many other asyncio objects.

To make sure each object is bound to new event loop, it's better to create asyncio-related objects already after you set and ran new event loop. It'll look like this:

async def main():
    proxies = asyncio.Queue()
    broker = Broker(proxies)
    return await asyncio.gather(
        broker.find(
            types = ['HTTPS'], 
            strict = True, 
            limit = amount
        ),
        self.storeProxies(proxies)
    )


if os.name == 'nt':
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Sometimes (rarely) you'll have to place some imports inside main() either.


Upd:

Problem happens because you change event loop between fetchProxies calls, but Broker imported only once (Python caches imported modules).

Reloading Broker didn't work for me thus I couldn't find a better way than to reuse event loop you set once.

Replace this code

if os.name == 'nt':
    loop = asyncio.SelectorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

with this

if os.name == 'nt':
    loop = asyncio.get_event_loop()
    if not isinstance(loop, asyncio.SelectorEventLoop):
        loop = asyncio.SelectorEventLoop() # for subprocess' pipes on Windows
        asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

P.S.

BTW you don't have to do this in the first place:

if os.name == 'nt':
    loop = asyncio.SelectorEventLoop()
    asyncio.set_event_loop(loop)

Windows already use SelectorEventLoop as default and it doesn't support pipes (doc).

Mikhail Gerasimov
  • 36,989
  • 16
  • 116
  • 159
  • Wow thank you so much for that answer! It does indeed seem to change the behavior but not I get a lot of ```File "d:\users\me\anaconda3\lib\asyncio\events.py", line 505, in add_reader raise NotImplementedError NotImplementedError``` –  Apr 06 '19 at 14:47
  • @FacPam it's due to `ProactorEventLoop` you set. Take a look at [doc](https://docs.python.org/3.6/library/asyncio-eventloops.html#windows): "add_reader() and add_writer() are not supported". I'm afraid you'll have to continue use default `SelectorEventLoop`. – Mikhail Gerasimov Apr 06 '19 at 14:54
  • @FacPam there're chances `ProxyBroker` creators didn't test it on Windows. It makes scene to post an [issue](https://github.com/constverum/ProxyBroker/issues) there. – Mikhail Gerasimov Apr 06 '19 at 14:56
  • Om my gosh it works! You are a true savior. So now I just have a few questions that I hope you will answer: 1) The linked answer in the OP suggested to use `ProactorEventLoop`, so why does this also work with `SelectorEventLoop`? 2) Sometimes, at the line `proxy = await proxies.get()` (at least that is what the stack trace claims), I get ```File "d:\users\nichlasdesktop\anaconda3\lib\asyncio\base_events.py", line 469, in _check_closed raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed``` - why? –  Apr 06 '19 at 15:02
  • Oh no, actually, now there are no proxies being stored (might have something to do with the error on the line in `storeProxies`) - `self.proxies` never contains any elements. Please let me steal just a little more of your time :)) –  Apr 06 '19 at 15:05
  • @FacPam I've just created and ran [this example](https://pastebin.com/DYQuCZ2i) on Windows and it works fine. I'll need fully reproducible example of your code that doesn't work, otherwise I can't guess where problem is. – Mikhail Gerasimov Apr 06 '19 at 15:13
  • @FacPam [here's little example](https://pastebin.com/a1dSm3WT) that stores proxies in variable instead of printing them one by one immediately. – Mikhail Gerasimov Apr 06 '19 at 15:18
  • I really appreciate that you will do you that to help me! I see what you mean - the examples also work on my Windows pc. Let me play with it for some time and then get back to you :) –  Apr 06 '19 at 15:22
  • @FacPam true. `proxybroker` creates something `asyncio`-related on import stage. It's not a usual thing, but can be avoided placing import after event loop is running - [example](https://pastebin.com/7TvpTTmn) – Mikhail Gerasimov Apr 06 '19 at 15:35
  • Marvelous. Let me try something then. I'll be back in a moment –  Apr 06 '19 at 15:44
  • Great, I have now done some tests. I have now updated the OP to show my current code based on your amazing inputs. However, this works perfectly the first time it is run, but then `fetchProxies` is called again after a few seconds and I get warnings followed by a behavior that acts like an infinite loop. Please take a look at my updated OP. –  Apr 06 '19 at 19:07
  • Perfect. Now one FINAL problem: Because that Proactor is not used (I think), the first problem mentioned in the OP reoccurs: `[WinError 10038] An operation was attempted on something that is not a socket`. This error was the reason why I ended up at [that answer](https://stackoverflow.com/questions/28642695/asyncio-error-an-operation-was-attempted-on-something-that-is-not-a-socket/28643127#28643127). It's quite unfortunate that one fix for one problem causes another problem. –  Apr 06 '19 at 20:48
  • Is it possible to fix if usage of `ProactorEventLoop` causes `NotImplemented` and this is fixed by not using `SelectorEventLoop` which then causes `OSError: [WinError 10038]` for which the fix is to not use `ProactorEventLoop` (based on the linked answer) and so it loops... –  Apr 06 '19 at 20:51
  • @FacPam no, I think code you use can't work `ProactorEventLoop`. If you need both `Broker` and pipes simultaneously, you should run your code on another OS of find relevant third-party event loop implementation for Windows (I don't know any). – Mikhail Gerasimov Apr 06 '19 at 21:47
  • Good. Thank you SOOOO much! Only 0.01% of the SO users are as kind as you, even though you think the answers may be obvious. God bless you –  Apr 06 '19 at 22:05