Python thread blocks after getting from Queue - python

I have a list of emails i want to validate from same domain. Firstly, I check if the domain allows verfication or is a catchall (accepts all email user as valid). E.g Assuming [a#domain.com, b#domain.com] is the list, I will check if foo-fake#domain.com would be valid, if it is return from function.
If not use multiple thread to verify all emails in list - if all fail return the last item. If one is valid and other threads are running stop them and return the valid one.
from Queue import Queue
import threading
import smtplib
class MailWorker(threading.Thread):
kill = False
def __init__(self, in_que, out_que):
super(MailWorker, self).__init__()
self.in_que = in_que
self.out_que = out_que
def run(self):
while True:
email, host = self.in_que.get()
self.test_email(email, host)
self.in_que.task_done()
def test_email(self, email, host, retry=0):
status = "Unknown"
code = None
rand = "info#example.com"
try:
server = smtplib.SMTP(timeout=20)
server.connect(host, 25)
server.ehlo_or_helo_if_needed()
code, response = server.docmd('mail from:', "<{}>".format(rand))
code, response = server.docmd('rcpt to:', "<{}>".format(email))
if code == 421:
while retry < 3:
if retry >= 3:
server.quit()
self.out_que.put((email, "Service not available", code))
server.quit()
return self.test_email(email, host, retry=retry)
if code == 250:
status = 'valid'
self.out_que.put((email, status, code,))
except smtplib.SMTPServerDisconnected:
while retry < 3:
retry += 1
status = "(SMTP Disconnected Unexpectedly) Retry # {}".format(retry)
code = -2
time.sleep(2)
if retry >= 3:
self.out_que.put((email, "SMTP Disconnected", code))
else:
return self.test_email(email, host, retry=retry)
self.out_que.put((email, status, code,))
def check_email(emails, domain, index=0, is_main=False):
email = status = code = None
in_que = Queue(maxsize=10)
out_que = Queue(maxsize=10)
if 'brighthouse' in domain:
host = 'brighthouse-co-uk.mail.protection.outlook.com'
else:
host = 'eu-smtp-inbound-2.mimecast.com'
# is it a catchall? if it is i want to return from the function ---
# If the email is valid then it is not a catchall all so execute line 91
# till return checking multipe emails in threads but exit when one valid is found else do all email in list
if not is_main: # check if the email is main
in_que.put(('JUNK_EMAIL_CANT_BE_REAL_fewfwewefew#' + domain, host)) # put rubbish email in thread if valid it is a catchall, then exit
for i in range(1):
mw = MailWorker(in_que, out_que)
print mw
print "*" * 20
mw.daemon = True
mw.start()
print mw.getName()
print in_que.qsize(), " in queue size"
print out_que.qsize(), " out queue size"
print "*" * 20
email, status, code = out_que.get()
print "Contet = ", email, status, code
if code == 250:
print 'Domain is a Catch-All. email: %s host: %s' % (emails[0], host)
MailWorker.kill = True
return emails, "catchall", -99, index
elif code == -1:
return email, status, code, index
# in_que.join()
# out_que.join()
for index, email_address in enumerate(emails):
in_que.put((email_address, host,))
for i in range(10):
mw = MailWorker(in_que, out_que)
mw.daemon = True
mw.start()
while not out_que.empty():
email, status, code, index = out_que.get()
if code == 250:
MailWorker.kill = True
return email, status, code, index
in_que.join()
out_que.join()
return email, status, code, index
emails_list = [
['fred#brighthouse.co.uk', 'joe.fred#brighthouse.co.uk', 'joe#brighthouse.co.uk'],
['fred#cqs.com', 'joe.fred#cqs.com', 'joe#cqs.com']
]
for emails in emails_list:
domain = emails[0].split('#')[1]
print(check_email(emails, domain))
My expectation is for the next list item to run.
The result with the above code is:
# CODE FREEZES and DOESN'T RUN SECOND item IN EMAILS_LIST -- SEE output
"""
<MailWorker(Thread-1, initial)>
********************
Thread-1
1 in queue size
0 out queue size
********************
Contet = rubbish_fQ94hEAi93#brighthouse.co.uk valid 250
Domain is a Catch-All. email: fred#brighthouse.co.uk host: brighthouse-co-uk.mail.protection.outlook.com
(['fred#brighthouse.co.uk', 'joe.fred#brighthouse.co.uk', 'joe#brighthouse.co.uk'], 'catchall', -99, 0)
<MailWorker(Thread-2, initial)>
********************
Thread-2
0 in queue size
0 out queue size
******************** <---- code blocks here
"""

Related

IBM Stats subscription topic always returns Reason 2033: FAILED: MQRC_NO_MSG_AVAILABLE

I am attempting to port some old java code to python.
I am using pymqi to connect to a queue manager and query for all messageflow statistics topics using the topic string: $SYS/Broker/+/StatisticsAccounting/Archive/#
When using the existing java program messages are read from the topic without issue.
When using the new python code it is able to connect and query the topic without issue but always gives the message
Reason 2033: FAILED: MQRC_NO_MSG_AVAILABLE
Stats messages are published by the broker for each messageflow every 10 minutes, and I have left the new code running for over 30minutes, never having received a message.
I've also tried setting
get_opts['WaitInterval'] = pymqi.CMQC.MQWI_UNLIMITED
and sitting around for 20minutes rather than using a loop, but no luck.
Is there any IIB server config that might be impacting the messages that I am able to see, or are there other options I should be using within the client?
import pymqi
queue_manager = 'MYQM'
channel = 'MYAPP.SVRCONN'
host = 'MYHOST'
port = 'MYPORT'
topic_string = '$SYS/Broker/+/StatisticsAccounting/Archive/#'
conn_info = '%s(%s)' % (host, port)
user = ""
password = ""
qmgr = pymqi.QueueManager(None)
qmgr.connect_tcp_client(queue_manager, pymqi.CD(), channel, conn_info, user, password)
sub_desc = pymqi.SD()
sub_desc['Options'] = pymqi.CMQC.MQSO_CREATE + pymqi.CMQC.MQSO_RESUME + pymqi.CMQC.MQSO_MANAGED
sub_desc.set_vs('SubName', 'apptest')
sub_desc.set_vs('ObjectString', topic_string)
sub = pymqi.Subscription(qmgr)
sub.sub(sub_desc=sub_desc)
get_opts = pymqi.GMO(Options=pymqi.CMQC.MQGMO_WAIT)
get_opts['WaitInterval'] = 10000
md = pymqi.md()
keep_running = True
while keep_running:
try:
# Reset the MsgId, CorrelId & GroupId so that we can reuse
# the same 'md' object again.
md.MsgId = pymqi.CMQC.MQMI_NONE
md.CorrelId = pymqi.CMQC.MQCI_NONE
md.GroupId = pymqi.CMQC.MQGI_NONE
message = sub.get(None, md, get_opts)
print('Have message from Queue')
print(message)
except pymqi.MQMIError as e:
if e.comp == pymqi.CMQC.MQCC_FAILED and e.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE:
print("no message?")
print(e)
pass
else:
# Some other error condition.
raise
except (UnicodeDecodeError, ValueError) as e:
print('Message is not valid json')
print(e)
print(message)
continue
except KeyboardInterrupt:
print('Have received a keyboard interrupt')
keep_running = False
sub.close(sub_close_options=0,close_sub_queue=True)
qmgr.disconnect()

Python if statement doesn't recognize bluetooth beacon

Here's the ScanUtility.py file that the BeaconScanner.py file uses to find and list the ble beacons.
#This is a working prototype. DO NOT USE IT IN LIVE PROJECTS
import sys
import struct
import bluetooth._bluetooth as bluez
OGF_LE_CTL=0x08
OCF_LE_SET_SCAN_ENABLE=0x000C
def hci_enable_le_scan(sock):
hci_toggle_le_scan(sock, 0x01)
def hci_disable_le_scan(sock):
hci_toggle_le_scan(sock, 0x00)
def hci_toggle_le_scan(sock, enable):
cmd_pkt = struct.pack("<BB", enable, 0x00)
bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, cmd_pkt)
def packetToString(packet):
"""
Returns the string representation of a raw HCI packet.
"""
if sys.version_info > (3, 0):
return ''.join('%02x' % struct.unpack("B", bytes([x]))[0] for x in packet)
else:
return ''.join('%02x' % struct.unpack("B", x)[0] for x in packet)
def parse_events(sock, loop_count=100):
old_filter = sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14)
flt = bluez.hci_filter_new()
bluez.hci_filter_all_events(flt)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt )
results = []
for i in range(0, loop_count):
packet = sock.recv(255)
ptype, event, plen = struct.unpack("BBB", packet[:3])
packetOffset = 0
dataString = packetToString(packet)
"""
If the bluetooth device is an beacon then show the beacon.
"""
#print (dataString)
if dataString[34:50] == '0303aafe1516aafe' or '0303AAFE1116AAFE':
"""
Selects parts of the bluetooth packets.
"""
broadcastType = dataString[50:52]
if broadcastType == '00' :
type = "Eddystone UID"
namespace = dataString[54:74].upper()
instance = dataString[74:86].upper()
resultsArray = [
{"type": type, "namespace": namespace, "instance": instance}]
return resultsArray
elif broadcastType == '10':
type = "Eddystone URL"
urlprefix = dataString[54:56]
if urlprefix == '00':
prefix = 'http://www.'
elif urlprefix == '01':
prefix = 'https://www.'
elif urlprefix == '02':
prefix = 'http://'
elif urlprefix == '03':
prefix = 'https://'
hexUrl = dataString[56:][:-2]
url = prefix + hexUrl.decode("hex")
rssi, = struct.unpack("b", packet[packetOffset -1])
resultsArray = [{"type": type, "url": url}]
return resultsArray
elif broadcastType == '20':
type = "Eddystone TLM"
resultsArray = [{"type": type}]
return resultsArray
elif broadcastType == '30':
type = "Eddystone EID"
resultsArray = [{"type": type}]
return resultsArray
elif broadcastType == '40':
type = "Eddystone RESERVED"
resultsArray = [{"type": type}]
return resultsArray
if dataString[38:46] == '4c000215':
"""
Selects parts of the bluetooth packets.
"""
type = "iBeacon"
uuid = dataString[46:54] + "-" + dataString[54:58] + "-" + dataString[58:62] + "-" + dataString[62:66] + "-" + dataString[66:78]
major = dataString[78:82]
minor = dataString[82:86]
majorVal = int("".join(major.split()[::-1]), 16)
minorVal = int("".join(minor.split()[::-1]), 16)
"""
Organises Mac Address to display properly
"""
scrambledAddress = dataString[14:26]
fixStructure = iter("".join(reversed([scrambledAddress[i:i+2] for i in range(0, len(scrambledAddress), 2)])))
macAddress = ':'.join(a+b for a,b in zip(fixStructure, fixStructure))
rssi, = struct.unpack("b", packet[packetOffset -1])
resultsArray = [{"type": type, "uuid": uuid, "major": majorVal, "minor": minorVal, "rssi": rssi, "macAddress": macAddress}]
return resultsArray
return results
The orginal Beaconscanner.py file works as it should by listing the beacons.
import ScanUtility
import bluetooth._bluetooth as bluez
#Set bluetooth device. Default 0.
dev_id = 0
try:
sock = bluez.hci_open_dev(dev_id)
print ("\n *** Looking for BLE Beacons ***\n")
print ("\n *** CTRL-C to Cancel ***\n")
except:
print ("Error accessing bluetooth")
ScanUtility.hci_enable_le_scan(sock)
#Scans for iBeacons
try:
while True:
returnedList = ScanUtility.parse_events(sock, 10)
for item in returnedList:
print(item)
print("")
except KeyboardInterrupt:
pass
Here's the modified BeaconScanner.py file which should print "Works" if the scanner finds the wanted beacon by it's mac address.
import ScanUtility
import bluetooth._bluetooth as bluez
#Set bluetooth device. Default 0.
dev_id = 0
try:
sock = bluez.hci_open_dev(dev_id)
print ("\n *** Looking for BLE Beacons ***\n")
print ("\n *** CTRL-C to Cancel ***\n")
except:
print ("Error accessing bluetooth")
ScanUtility.hci_enable_le_scan(sock)
#Scans for iBeacons
try:
while True:
returnedList = ScanUtility.parse_events(sock, 10)
for macAddress in returnedList:
if macAddress == "e2:e3:23:d1:b0:54":
print("Works")
else:
print("Nope")
except KeyboardInterrupt:
pass
The modified file however always prints "Nope". I think the "macAddress" part in the if statement can't be used to identify the beacons. What have to be changed in the code so the beacon can be identified by it's mac address in the if statement?
According to the source of ScanUtility.py, it seems like the function returns a list of one dict which is a bit odd. You should query the dict as follow:
for item in returnedList:
try:
if item['macAddress'] == "e2:e3:23:d1:b0:54":
print("Works")
else:
print("Nope")
except KeyError:
print('MAC Address is missing')
Note that I have added a try/except statement to deal with cases where the macAddress key is not present in your dict. This works only if your dict is not a subclass of defaultdict.
Searching for a beacon by its mac address is not always a good solution as it is possible a beacon is using a random private addresses.
Are you sure that the mac address you are looking for is ever broadcast?
Your code also only seems to return the mac address for iBeacons.
The other thing I noticed about this code is that it bypasses the bluetoothd running on your system by doing direct calls to the hci socket. This is generally not a good idea and requires the python script to be run with root priveliages.
A way to avoid this is use the BlueZ D-Bus API. An example of this is included below and prints out beacon data plus a message when it sees the mac address of interest. This code requires pydbus and gi.repository
import argparse
from gi.repository import GLib
from pydbus import SystemBus
import uuid
DEVICE_INTERFACE = 'org.bluez.Device1'
remove_list = set()
def stop_scan():
"""Stop device discovery and quit event loop"""
adapter.StopDiscovery()
mainloop.quit()
def clean_beacons():
"""
BlueZ D-Bus API does not show duplicates. This is a
workaround that removes devices that have been found
during discovery
"""
not_found = set()
for rm_dev in remove_list:
try:
adapter.RemoveDevice(rm_dev)
except GLib.Error as err:
not_found.add(rm_dev)
for lost in not_found:
remove_list.remove(lost)
def process_eddystone(data):
"""Print Eddystone data in human readable format"""
_url_prefix_scheme = ['http://www.', 'https://www.',
'http://', 'https://', ]
_url_encoding = ['.com/', '.org/', '.edu/', '.net/', '.info/',
'.biz/', '.gov/', '.com', '.org', '.edu',
'.net', '.info', '.biz', '.gov']
tx_pwr = int.from_bytes([data[1]], 'big', signed=True)
# Eddystone UID Beacon format
if data[0] == 0x00:
namespace_id = int.from_bytes(data[2:12], 'big')
instance_id = int.from_bytes(data[12:18], 'big')
print(f'\t\tEddystone UID: {namespace_id} - {instance_id} \u2197 {tx_pwr}')
# Eddystone URL beacon format
elif data[0] == 0x10:
prefix = data[2]
encoded_url = data[3:]
full_url = _url_prefix_scheme[prefix]
for letter in encoded_url:
if letter < len(_url_encoding):
full_url += _url_encoding[letter]
else:
full_url += chr(letter)
print(f'\t\tEddystone URL: {full_url} \u2197 {tx_pwr}')
def process_ibeacon(data, beacon_type='iBeacon'):
"""Print iBeacon data in human readable format"""
beacon_uuid = uuid.UUID(bytes=bytes(data[2:18]))
major = int.from_bytes(bytearray(data[18:20]), 'big', signed=False)
minor = int.from_bytes(bytearray(data[20:22]), 'big', signed=False)
tx_pwr = int.from_bytes([data[22]], 'big', signed=True)
print(f'\t\t{beacon_type}: {beacon_uuid} - {major} - {minor} \u2197 {tx_pwr}')
def ble_16bit_match(uuid_16, srv_data):
"""Expand 16 bit UUID to full 128 bit UUID"""
uuid_128 = f'0000{uuid_16}-0000-1000-8000-00805f9b34fb'
return uuid_128 == list(srv_data.keys())[0]
def on_iface_added(owner, path, iface, signal, interfaces_and_properties):
"""
Event handler for D-Bus interface added.
Test to see if it is a new Bluetooth device
"""
iface_path, iface_props = interfaces_and_properties
if DEVICE_INTERFACE in iface_props:
on_device_found(iface_path, iface_props[DEVICE_INTERFACE])
def on_device_found(device_path, device_props):
"""
Handle new Bluetooth device being discover.
If it is a beacon of type iBeacon, Eddystone, AltBeacon
then process it
"""
address = device_props.get('Address')
address_type = device_props.get('AddressType')
name = device_props.get('Name')
alias = device_props.get('Alias')
paired = device_props.get('Paired')
trusted = device_props.get('Trusted')
rssi = device_props.get('RSSI')
service_data = device_props.get('ServiceData')
manufacturer_data = device_props.get('ManufacturerData')
if address.casefold() == 'e2:e3:23:d1:b0:54':
print('Found mac address of interest')
if service_data and ble_16bit_match('feaa', service_data):
process_eddystone(service_data['0000feaa-0000-1000-8000-00805f9b34fb'])
remove_list.add(device_path)
elif manufacturer_data:
for mfg_id in manufacturer_data:
# iBeacon 0x004c
if mfg_id == 0x004c and manufacturer_data[mfg_id][0] == 0x02:
process_ibeacon(manufacturer_data[mfg_id])
remove_list.add(device_path)
# AltBeacon 0xacbe
elif mfg_id == 0xffff and manufacturer_data[mfg_id][0:2] == [0xbe, 0xac]:
process_ibeacon(manufacturer_data[mfg_id], beacon_type='AltBeacon')
remove_list.add(device_path)
clean_beacons()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--duration', type=int, default=0,
help='Duration of scan [0 for continuous]')
args = parser.parse_args()
bus = SystemBus()
adapter = bus.get('org.bluez', '/org/bluez/hci0')
bus.subscribe(iface='org.freedesktop.DBus.ObjectManager',
signal='InterfacesAdded',
signal_fired=on_iface_added)
mainloop = GLib.MainLoop()
if args.duration > 0:
GLib.timeout_add_seconds(args.duration, stop_scan)
adapter.SetDiscoveryFilter({'DuplicateData': GLib.Variant.new_boolean(True)})
adapter.StartDiscovery()
try:
print('\n\tUse CTRL-C to stop discovery\n')
mainloop.run()
except KeyboardInterrupt:
stop_scan()
Example invocation and output:
$ python3 beacon_scanner.py
Use CTRL-C to stop discovery
iBeacon: 1e9fdc8c-96e0-4d68-b34a-3b635cec0489 - 5555 - 99 ↗ -65
Eddystone URL: http://www.bluetooth.com/ ↗ -69
Found mac address of interest

How to set one instance of imaplib mailbox for few threads?

How can i set one mailbox parser for user in few different threads ? Each user have 2 or more companies which mails he should parse. In my expample i'm always had errors.
class User():
services = {'company1': 'STOPED',
'company2': 'STOPED'}
def __init__(self, user_settings):
self.user_name = user_settings['User']
self.user_settings = user_settings
self.global_mailbox = None
def company1(self):
service_name = 'company1'
settings = self.user_settings['Company1']
gb_mail = False
def mailbox_check(mailbox):
nonlocal settings, service_name
mailbox.noop()
status, mails = mailbox.search(None, '(UNSEEN)', '(FROM "company1#cmp.com")')
....
if not settings['Mail Login']:
if self.global_mailbox:
mailbox = self.global_mailbox
gb_mail = True
else:
self.SET_GLOBAL_MAIL()
if not self.global_mailbox:
return
else:
mailbox = self.global_mailbox
else:
mail_host = 'imap.{0}'.format(settings['Mail Login'].split('#')[-1])
mail_login = settings['Mail Login']
mail_password = settings['Mail Password']
mailbox = imaplib.IMAP4_SSL(mail_host)
mailbox.sock.settimeout(43200)
mailbox.login(mail_login, mail_password)
mailbox.select('INBOX')
gb_mail = False
while self.services[service_name] != 'STOPED':
time.sleep(5)
new_orders = self.mailbox_check(mailbox)
if new_orders:
action()
if self.services[service_name] == 'STOPED':
break
def company2(self):
service_name = 'company2'
settings = self.user_settings['Company2']
gb_mail = False
def mailbox_check(mailbox):
nonlocal settings, service_name
mailbox.noop()
status, mails = mailbox.search(None, '(UNSEEN)', '(FROM "company2#cmp.com")')
....
if not settings['Mail Login']:
if self.global_mailbox:
mailbox = self.global_mailbox
gb_mail = True
else:
self.SET_GLOBAL_MAIL()
if not self.global_mailbox:
return
else:
mailbox = self.global_mailbox
else:
mail_host = 'imap.{0}'.format(settings['Mail Login'].split('#')[-1])
mail_login = settings['Mail Login']
mail_password = settings['Mail Password']
mailbox = imaplib.IMAP4_SSL(mail_host)
mailbox.sock.settimeout(43200)
mailbox.login(mail_login, mail_password)
mailbox.select('INBOX')
gb_mail = False
while self.services[service_name] != 'STOPED':
time.sleep(5)
new_orders = self.mailbox_check(mailbox)
if new_orders:
action()
if self.services[service_name] == 'STOPED':
break
def SET_GLOBAL_MAIL(self)
try:
gb_mail = self.user_settings['Global Mail']
mail_host = 'imap.{0}'.format(gb_mail['Login'].split('#')[-1])
mail_login = gb_mail['Login']
mail_password = gb_mail['Password']
mailbox = imaplib.IMAP4_SSL(mail_host)
mailbox.sock.settimeout(43200)
mailbox.login(mail_login, mail_password)
mailbox.select('INBOX')
self.global_mailbox = mailbox
except:
self.global_mailbox = None
pass
def START_ALL(self):
self.SET_GLOBAL_MAIL()
for service in self.services.keys():
self.services[service] = 'RUNNING'
threading.Thread(target=lambda: self.__getattribute__(service)(), name='{0} [{1} service thread]'.format(self.user_name, service), daemon=True).start()
>>>user = User(settings)
>>>user.START_ALL()
After few seconds i got these errors:
imaplib.IMAP4.abort: command: SEARCH => socket error: EOF
imaplib.IMAP4.abort: socket error: EOF
imaplib.IMAP4.abort: command: NOOP => socket error: EOF
imaplib.IMAP4.abort: socket error: [WinError 10014] The system detected an
invalid pointer address in attempting to use a pointer argument in a call
ssl.SSLError: [SSL: SSLV3_ALERT_BAD_RECORD_MAC] sslv3 alert bad record mac (_ssl.c:2273)
If for each thread i'm creating a new imap session all works fine, but GMAIL has a limit for simultaneous connection through imap. And user may have more than 15 companies for parsing. How to setup one global mail for user for all his actions ?
It does not make really sense to use the same IMAP connection for several conversations because there is one single socket connection and one single server side context. If one thread asks mailbox1 and a second asks for mailbox2, the server will select successively the 2 mailboxes and will stay in last one.
Not speaking of race conditions if two threads simultaneously read from same socket: each will only get quasi random partial data while the other part will be read by the other thread. I am sorry but this is not possible.

Device twin Reported properties are not updating properly with python sdk

I had divided my software update process in various stages like (download, unzip, pre-install, install, post-install). I am setting reported properties
at every stage accordingly. But these properties are not updating during installation process (i.e. unable to see changes in reported property in device twin on azure portal) but at the end of installation I am getting callback responses for all the set "reported" properties.
I am working on software update with Azure IOT using python device sdk.
For this I have modified the sample given in SDK (i.e. iothub_client_sample_class.py file). I am using device twin for updating the software. I had created "desired" property for "software_version" in device twin. Once "desired" property for "software_version" is changed, software update process is started. Software update process perform various operation so I have divided this process in various stages. I am sending "reported" properties for ever stage to IotHub. But these "reported" are not updating in seqence in device twin reported property on azure portal.
import random
import time
import sys
import iothub_client
import json
from iothub_client import IoTHubClient, IoTHubClientError, IoTHubTransportProvider
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError, DeviceMethodReturnValue
from iothub_client_args import get_iothub_opt, OptionError
# HTTP options
# Because it can poll "after 9 seconds" polls will happen effectively
# at ~10 seconds.
# Note that for scalabilty, the default value of minimumPollingTime
# is 25 minutes. For more information, see:
# https://azure.microsoft.com/documentation/articles/iot-hub-devguide/#messaging
TIMEOUT = 241000
MINIMUM_POLLING_TIME = 9
# messageTimeout - the maximum time in milliseconds until a message times out.
# The timeout period starts at IoTHubClient.send_event_async.
# By default, messages do not expire.
MESSAGE_TIMEOUT = 1000
RECEIVE_CONTEXT = 0
AVG_WIND_SPEED = 10.0
MIN_TEMPERATURE = 20.0
MIN_HUMIDITY = 60.0
MESSAGE_COUNT = 5
RECEIVED_COUNT = 0
TWIN_CONTEXT = 0
METHOD_CONTEXT = 0
# global counters
RECEIVE_CALLBACKS = 0
SEND_CALLBACKS = 0
BLOB_CALLBACKS = 0
TWIN_CALLBACKS = 0
SEND_REPORTED_STATE_CALLBACKS = 0
METHOD_CALLBACKS = 0
firstTime = True
hub_manager = None
PROTOCOL = IoTHubTransportProvider.MQTT
CONNECTION_STRING = "XXXXXX"
base_version = '1.0.0.000'
SUCCESS = 0
firstTime = True
def downloadImage(url):
# Code for downloading the package from url
return 0
def unzipPackage():
#code for unzipping the package
return 0
def readPackageData():
# code reading package data
return 0
def pre_install():
#code for installing dependencies
return 0
def install():
#code for installing main package
return 0
def post_install():
#code for verifying installation
return 0
def start_software_update(url,message):
global hub_manager
print "Starting software update process!!!!"
reported_state = "{\"updateStatus\":\"softwareUpdateinprogress\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1003)
time.sleep(1)
status = downloadImage(url)
if status == SUCCESS:
reported_state = "{\"updateStatus\":\"downloadComplete\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1004)
print "Downlaod Phase Done!!!"
time.sleep(1)
else:
print "Download Phase failed!!!!"
return False
status = unzipPackage()
if status == SUCCESS:
reported_state = "{\"updateStatus\":\"UnzipComplete\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1005)
print "Unzip Package Done!!!"
time.sleep(1)
else:
print "Unzip package failed!!!"
return False
status = readPackageData()
if status == SUCCESS:
reported_state = "{\"updateStatus\":\"ReadPackageData\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1006)
print "Reading package json data"
time.sleep(1)
else:
print "Failed Reading package!!!"
return False
status = pre_install()
if status == SUCCESS:
reported_state = "{\"updateStatus\":\"PreInstallComplete\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1007)
time.sleep(1)
print "pre_install state successful!!!"
else:
print "pre_install failed!!!!"
return False
status = install()
if status == SUCCESS:
reported_state = "{\"updateStatus\":\"InstallComplete\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1008)
time.sleep(1)
print "install sucessful!!!"
else:
print "install failed!!!"
return False
status = post_install()
if status == SUCCESS:
reported_state = "{\"updateStatus\":\"SoftwareUpdateComplete\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1009)
time.sleep(1)
print "post install sucessful!!!"
else:
print "post install failed!!!"
return False
return True
def device_twin_callback(update_state, payload, user_context):
global TWIN_CALLBACKS
global firstTime
global base_version
print ( "\nTwin callback called with:\nupdateStatus = %s\npayload = %s\ncontext = %s" % (update_state, payload, user_context) )
TWIN_CALLBACKS += 1
print ( "Total calls confirmed: %d\n" % TWIN_CALLBACKS )
message = json.loads(payload)
if not firstTime:
if message["software_version"] != base_version:
url = message["url"]
status = start_software_update(url,message)
if status:
print "software Update Successful!!!"
else:
print "software Update Unsuccessful!!!"
else:
base_version = message["desired"]["software_version"]
print "Set firstTime to false", base_version
firstTime = False
def send_reported_state_callback(status_code, user_context):
global SEND_REPORTED_STATE_CALLBACKS
print ( "Confirmation for reported state received with:\nstatus_code = [%d]\ncontext = %s" % (status_code, user_context) )
SEND_REPORTED_STATE_CALLBACKS += 1
print ( " Total calls confirmed: %d" % SEND_REPORTED_STATE_CALLBACKS )
class HubManager(object):
def __init__(
self,
connection_string,
protocol=IoTHubTransportProvider.MQTT):
self.client_protocol = protocol
self.client = IoTHubClient(connection_string, protocol)
if protocol == IoTHubTransportProvider.HTTP:
self.client.set_option("timeout", TIMEOUT)
self.client.set_option("MinimumPollingTime", MINIMUM_POLLING_TIME)
# set the time until a message times out
self.client.set_option("messageTimeout", MESSAGE_TIMEOUT)
# some embedded platforms need certificate information
# self.set_certificates()
self.client.set_device_twin_callback(device_twin_callback, TWIN_CONTEXT)
def send_reported_state(self, reported_state, size, user_context):
self.client.send_reported_state(
reported_state, size,
send_reported_state_callback, user_context)
def main(connection_string, protocol):
global hub_manager
try:
print ( "\nPython %s\n" % sys.version )
print ( "IoT Hub Client for Python" )
hub_manager = HubManager(connection_string, protocol)
print ( "Starting the IoT Hub Python sample using protocol %s..." % hub_manager.client_protocol )
reported_state = "{\"updateStatus\":\"waitingforupdate\"}"
hub_manager.send_reported_state(reported_state, len(reported_state), 1002)
while True:
time.sleep(1)
except IoTHubError as iothub_error:
print ( "Unexpected error %s from IoTHub" % iothub_error )
return
except KeyboardInterrupt:
print ( "IoTHubClient sample stopped" )
if __name__ == '__main__':
try:
(CONNECTION_STRING, PROTOCOL) = get_iothub_opt(sys.argv[1:], CONNECTION_STRING)
except OptionError as option_error:
print ( option_error )
usage()
sys.exit(1)
main(CONNECTION_STRING, PROTOCOL)
Expected Result: The "reported" property for every stage in software update should update properly in device twin in azure portal.
Actual Result: The "reported" property for each stage in software update process is not updating properly.

AWS EC2: How to prevent infinite loop for instance status check?

I have the following python boto3 code with a potentially infinite while-loop. Generally, after a few minutes the while-loop succeeds. However, if something fails on the AWS side the program could hang for an indefinite period.
I am sure that this is not the most appropriate way to do this.
# credentials stored in ../.aws/credentials
# region stored in ../.aws/config
# builtins
from time import sleep
# plugins
import boto3
# Assign server instance IDs.
cye_production_web_server_2 = 'i-FAKE-ID'
# Setup EC2 client
ec2 = boto3.client('ec2')
# Start the second web server.
start_response = ec2.start_instances(
InstanceIds=[cye_production_web_server_2, ],
DryRun=False
)
print(
'instance id:',
start_response['StartingInstances'][0]['InstanceId'],
'is',
start_response['StartingInstances'][0]['CurrentState']['Name']
)
# Wait until status is 'ok'
status = None
while status != 'ok':
status_response = ec2.describe_instance_status(
DryRun=False,
InstanceIds=[cye_production_web_server_2, ],
)
status = status_response['InstanceStatuses'][0]['SystemStatus']['Status']
sleep(5) # 5 second throttle
print(status_response)
print('status is', status.capitalize())
Implement a counter in the loop and fail after so many attempts
status = None
counter = 5
while (status != 'ok' and counter > 0):
status_response = ec2.describe_instance_status(
DryRun=False,
InstanceIds=[cye_production_web_server_2, ],
)
status = status_response['InstanceStatuses'][0]['SystemStatus']['Status']
sleep(5) # 5 second throttle
counter=counter-1
print(status_response)
print('status is', status.capitalize())
You could try doing it in a for loop instead with a fixed number of tries.
For example:
MAX_RETRIES = 5
# Try until status is 'ok'
for x in range(MAX_RETRIES):
status_response = ec2.describe_instance_status(
DryRun=False,
InstanceIds=[cye_production_web_server_2, ],
)
status = status_response['InstanceStatuses'][0]['SystemStatus']['Status']
if status != 'ok':
sleep(5) # 5 second throttle
else:
break
Use timeout might be a better idea
import time
systemstatus = False
timeout = time.time() + 60*minute
while systemstatus is not True:
status = ec2.describe_instance_status( \
DryRun = False,
InstanceIds = [instance_id]
)
if status['InstanceStatuses'][0]['SystemStatus']['Status'] == 'ok':
systemstatus = True
if time.time() > timeout:
break
else:
time.sleep(10)

Categories