Уведомления

Группа в Telegram: @pythonsu

#1 Март 17, 2019 18:43:51

InventoR
Зарегистрирован: 2015-11-08
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Асинхронная проверка DNS

Все привет, нужна помощь сообщества, осваиваю потихоньку асинхронность в python и есть задача написать проверку DNS серверов.
Использую сейчас следующий код (пожалуйста, не обращайте внимание на форматирование и качество кода, это тестовый вариант, потом будет приведен в порядок):

[code python]
#!/usr/bin/env python

import dns.resolver
from pprint import pprint
import random
import time
import asyncio
from datetime import datetime

DNS_RESOLVER = dns.resolver.Resolver()
name_server = ['192.168.5.254']

import platform
print(platform.python_version())

hosts = [
'microsoft.com',
'amazon.com',
'facebook.com',
'twitter.com',
'google.com',
'youtube.com',
'instagram.com',
'linkedin.com',
'wordpress.org',
'pinterest.com',
'wikipedia.org',
'wordpress.com',
'blogspot.com',
'apple.com',
'adobe.com',
'tumblr.com',
'youtu.be',
'amazon.com',
'goo.gl',
'vimeo.com',
'flickr.com',
'microsoft.com',
'yahoo.com',
'godaddy.com',
'qq.com',
'bit.ly',
'reddit.com',
'w3.org',
'baidu.com',
'nytimes.com',
't.co',
'europa.eu',
'buydomains.com',
'wp.com',
'statcounter.com',
'www.miitbeian.gov.cn',
'jimdo.com',
'blogger.com'
]

def random_delay():
return int(random.random() * 10)

format_len=max(hosts, key=len)
import async_timeout

async def resolve_dns(record, delay=0):
print(f"Run dns_query for host: {record:<20s} with delay: {delay}".format(record, delay))
try:
await asyncio.sleep(delay)
with async_timeout.timeout(10):
answer = DNS_RESOLVER.query(record, "A")
rcode = dns.rcode.to_text(answer.response.rcode())
print("HOST: {0:<20s}, rcode: {1}, delay: {2}".format(record, rcode, delay))
except Exception as e:
print("Host: {0:<20s} has resolving issue: {1}".format(record, e))
# raise
else:
pass
finally:
pass

def main():
print("Run main function")
DNS_RESOLVER.timeout = 3
DNS_RESOLVER.nameservers = name_server
pprint(vars(DNS_RESOLVER), indent=2)

start = time.time()
tasks = []
loop = asyncio.get_event_loop()

try:
tasks = [
loop.create_task(resolve_dns(host, random_delay()))
for host in hosts
]
loop.run_until_complete(asyncio.gather(*tasks))
finally:
loop.close()


end = time.time()
print("Total time: {}".format(end - start))


if __name__ == "__main__":
print(f"{__file__} executed")
main()

[/code]

В этом коде все работает хорошо, ровно до тех пор пока указан работающий DNS сервер, который не имеет проблем с ответами.
Как только указать не работающий, пропадает вся магия асинхронности и запросы к dns идут последовательно, при этом отваливаются по timeout
[code python]Run dns_query for host: buydomains.com       with delay: 8
Run dns_query for host: wp.com with delay: 6
Run dns_query for host: statcounter.com with delay: 3
Run dns_query for host: www.miitbeian.gov.cn with delay: 6
Run dns_query for host: jimdo.com with delay: 5
Run dns_query for host: blogger.com with delay: 5
Host: wordpress.com has resolving issue: The DNS operation timed out after 30.002588987350464 seconds
Host: goo.gl has resolving issue: The DNS operation timed out after 30.00293493270874 seconds
Host: qq.com has resolving issue: The DNS operation timed out after 30.002574920654297 seconds
Host: bit.ly has resolving issue: The DNS operation timed out after 30.00347328186035 seconds
Host: reddit.com has resolving issue: The DNS operation timed out after 30.00317406654358 seconds
[/code]

Подскажите пожалуйста, как правильно переписать данный код для версии 3.6 чтобы timeout на какой-то из проверок не блокировал работу остальных потоков?

Отредактировано InventoR (Март 17, 2019 18:44:26)

Офлайн

#2 Март 19, 2019 07:29:20

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Асинхронная проверка DNS

а дайте ссылку на модуль для dns котоырй вы используете.



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#3 Март 19, 2019 11:23:51

InventoR
Зарегистрирован: 2015-11-08
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Асинхронная проверка DNS

Вот этот модуль:
http://www.dnspython.org/examples.html

но на сколько вижу он не поддерживает asyncio, соответственно наверное мне лучше поискать реализацию где уже есть поддержка async

Офлайн

#4 Март 19, 2019 12:00:59

aiscy
Зарегистрирован: 2015-06-17
Сообщения: 52
Репутация: +  9  -
Профиль   Отправить e-mail  

Асинхронная проверка DNS

Если ничего не напутал

 import asyncio
import logging
import async_timeout
import aiodns
hosts = [
    'microsoft.com',
    'amazon.com',
    'facebook.com',
    'twitter.com',
    'google.com',
    'youtube.com',
    'instagram.com',
    'linkedin.com',
    'wordpress.org',
    'pinterest.com',
    'wikipedia.org',
    'wordpress.coms',
    'blogspot.com',
    'apple.com',
    'adobe.com',
    'tumblr.com',
    'youtu.be',
    'amazon.com',
    'goo.gl',
    'vimeo.com',
    'flickr.com',
    'microsoft.com',
    'yahoo.com',
    'godaddy.com',
    'qq.com',
    'bit.ly',
    'reddit.com',
    'w3.org',
    'baidu.com',
    'nytimes.com',
    't.co',
    'europa.eu',
    'buydomains.com',
    'wp.com',
    'statcounter.com',
    'www.miitbeian.gov.cn',
    'jimdo.com',
    'blogger.com'
]
async def resolve_dns(resolver, record, record_type='A', timeout=10):
    try:
        with async_timeout.timeout(timeout):
            fields = await resolver.query(record, record_type)
            if fields:
                for field in fields:
                    logger.debug(f'Record: {record}, Address: {field.host}, TTL: {field.ttl}')
            else:
                logger.debug(f'Record {record} contains no fields.')
    except aiodns.error.DNSError as e:
        logger.error(f'Got error while querying {record} with type {record_type}. Error: {e}')
    except asyncio.TimeoutError:
        logger.error(f'Got timeout while querying {record} with type {record_type}.')
async def main():
    resolver = aiodns.DNSResolver(nameservers=['8.8.8.8'])
    broken_resolver = aiodns.DNSResolver(nameservers=['72.66.115.13'])
    tasks = [resolve_dns(resolver, host) for host in hosts]
    broken_tasks = [resolve_dns(broken_resolver, host) for host in hosts]
    for future in asyncio.as_completed(broken_tasks + tasks):
        await future
if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - [%(levelname)s] - %(message)s')
    logger = logging.getLogger()
    event_loop = asyncio.get_event_loop()
    event_loop.run_until_complete(main())

Офлайн

#5 Март 20, 2019 14:08:35

InventoR
Зарегистрирован: 2015-11-08
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

Асинхронная проверка DNS

aiscy
Если ничего не напутал
Спасибо огромное,
супер
Работает, почти то что надо
Теперь можно допилить и интегрировать с aws lambda, пушить метрики в cloudwatch и строить графики

Офлайн

#6 Март 20, 2019 17:15:11

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Асинхронная проверка DNS

Я именно это и предполагал. И дал верную наводку.



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version