Найти - Пользователи
Полная версия: Асинхронная проверка DNS
Начало » Python для новичков » Асинхронная проверка DNS
1
InventoR
Все привет, нужна помощь сообщества, осваиваю потихоньку асинхронность в 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 на какой-то из проверок не блокировал работу остальных потоков?
JOHN_16
а дайте ссылку на модуль для dns котоырй вы используете.
InventoR
Вот этот модуль:
http://www.dnspython.org/examples.html

но на сколько вижу он не поддерживает asyncio, соответственно наверное мне лучше поискать реализацию где уже есть поддержка async
aiscy
Если ничего не напутал
 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())
InventoR
aiscy
Если ничего не напутал
Спасибо огромное,
супер
Работает, почти то что надо
Теперь можно допилить и интегрировать с aws lambda, пушить метрики в cloudwatch и строить графики
JOHN_16
Я именно это и предполагал. И дал верную наводку.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB