123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- import os
- import uuid
- import time
- import sys
- from azure.storage.blob import BlockBlobService
- from azure.storage.common.models import LocationMode
- from azure.storage.common.retry import LinearRetry
- account_name = os.environ.get('accountname')
- account_key = os.environ.get('accountkey')
- retry_count = 0
- retry_threshold = 5
- secondary_read_count = 0
- secondary_threshold = 20
- blob_client = None
- container_name = None
- '''
- Main method. Sets up the objects needed, the performs a loop to perform blob
- operation repeatedly, responding to the Retry and Response Received events.
- '''
- def run_circuit_breaker():
-
- image_to_upload = "HelloWorld.png"
- global blob_client
- global container_name
- try:
-
- blob_client = BlockBlobService(account_name, account_key)
-
- container_name = "democontainer" + str(uuid.uuid4())
- blob_client.create_container(container_name)
- except Exception as ex:
- print("Please make sure you have put the correct storage account name and key.")
- print(ex)
-
- full_path_to_file = os.path.join(os.path.dirname(__file__), image_to_upload)
- blob_client.create_blob_from_path(container_name, image_to_upload, full_path_to_file)
-
- blob_client.location_mode = LocationMode.SECONDARY
- blob_client.retry = LinearRetry(backoff=0).retry
-
-
-
- counter = 0
- while counter < 60:
- counter += 1
- sys.stdout.write("\nAttempt {0} to see if the blob has replicated to the secondary storage yet.".format(counter))
- sys.stdout.flush()
- if blob_client.exists(container_name, image_to_upload):
- break
-
-
- time.sleep(1)
-
-
-
-
- blob_client.location_mode = LocationMode.PRIMARY
- blob_client.retry = LinearRetry(max_attempts=retry_threshold, backoff=1).retry
- '''
- ************INSTRUCTIONS**************k
- To perform the test, first replace the 'accountname' and 'accountkey' with your storage account name and key.
- Every time it calls get_blob_to_path it will hit the response_callback function.
- Next, run this app. While this loop is running, pause the program by pressing any key, and
- put the intercept code in Fiddler (that will intercept and return a 503).
- For instructions on modifying Fiddler, look at the Fiddler_script.text file in this project.
- There are also full instructions in the ReadMe_Instructions.txt file included in this project.
- After adding the custom script to Fiddler, calls to primary storage will fail with a retryable
- error which will trigger the Retrying event (above).
- Then it will switch over and read the secondary. It will do that 20 times, then try to
- switch back to the primary.
- After seeing that happen, pause this again and remove the intercepting Fiddler code
- Then you'll see it return to the primary and finish.
- '''
- print("\n\nThe application will pause at 200 unit interval")
- for i in range(0, 1000):
- if blob_client.location_mode == LocationMode.SECONDARY:
- sys.stdout.write("S{0} ".format(str(i)))
- else:
- sys.stdout.write("P{0} ".format(str(i)))
- sys.stdout.flush()
- try:
-
-
- blob_client.retry_callback = retry_callback
-
- blob_client.get_blob_to_path(container_name, image_to_upload,
- str.replace(full_path_to_file, ".png", "Copy.png"))
-
- if i == 200 or i == 400 or i == 600 or i == 800:
- sys.stdout.write("\nPress the Enter key to resume")
- sys.stdout.flush()
- if sys.version_info[0] < 3:
- raw_input()
- else:
- input()
- except Exception as ex:
- print(ex)
- finally:
-
- blob_client.response_callback = response_callback
-
- blob_client.delete_container(container_name)
- '''
- RequestCompleted Event handler
- If it's not pointing at the secondary, let it go through. It was either successful,
- or it failed with a non-retryable event.
- If it's pointing at the secondary, increment the read count.
- If the number of reads has hit the threshold of how many reads you want to do against the secondary,
- before you switch back to primary, switch back and reset the secondary_read_count.
- '''
- def response_callback(response):
- global secondary_read_count
- if blob_client.location_mode == LocationMode.SECONDARY:
-
-
- secondary_read_count += 1
- if secondary_read_count >= secondary_threshold:
- blob_client.location_mode = LocationMode.PRIMARY
- secondary_read_count = 0
- '''
- Retry Event handler
- If it has retried more times than allowed, and it's not already pointed to the secondary,
- flip it to the secondary and reset the retry count.
- If it has retried more times than allowed, and it's already pointed to the secondary throw an exception.
- '''
- def retry_callback(retry_context):
- global retry_count
- retry_count = retry_context.count
- sys.stdout.write("\nRetrying event because of failure reading the primary. RetryCount= {0}".format(retry_count))
- sys.stdout.flush()
-
- if retry_count >= retry_threshold:
-
- if blob_client.location_mode != LocationMode.SECONDARY:
- blob_client.location_mode = LocationMode.SECONDARY
- retry_count = 0
- else:
- raise Exception("Both primary and secondary are unreachable. "
- "Check your application's network connection.")
- if __name__ == '__main__':
- print("Azure storage Circuit Breaker Sample \n")
- try:
- run_circuit_breaker()
- except Exception as e:
- print("Error thrown = {0}".format(e))
- sys.stdout.write("\nPress any key to exit.")
- sys.stdout.flush()
- if sys.version_info[0]<3:
- raw_input()
- else:
- input()
|