API connection “retry logic with a cooldown period” simulator ( Python exercise )

This is a very simple API call “circuit-breaker” style simulator I’ve written in Python. But since it’s a stateless code snippet, you should call it most likely a “retry logic with a cooldown period” simulator. But there are valid use case scenarios when stateless is the desired state type. For example when a validation of a dataset against a service can either pass or fail and throw an exception and cause the execution flow to halt. This is typical for data-flow styled apps. In such case the circuit-open state is not acceptable. Anyway the goal is to make sure, that whenever we have a connection (or timeout) error during the API call ,we retry after 10 seconds, after 20 seconds, after 30 seconds and then quit trying. The ConnectionError exception is simulated using a non-routable address 10.255.255.1.

However in the microservices world, if you want to implement the full-scale state-full circuit-breaker, please have a look at this article.

import datetime
import time
import logging
import requests

iterator = 1
attempt = 1

# while cycle to simulate connection error using non-routable IP address
while iterator < 40:
    try:
        # if iterator inside the range to simulate success
        if 1 < iterator < 8:
            r = requests.get('https://data.police.uk/api/crimes-at-location?date=2017-02&location_id=884227')
        # else iterator outside the range to simulate the error event
        else:
            r = requests.get('http://10.255.255.1')
        if r.status_code != requests.codes.ok:
            logging.error('Wrong request status code received, %s', r.status_code)
        r = r.json()
        print(r)
        attempt = 1
    except (requests.exceptions.ConnectionError, requests.exceptions.Timeout,
            requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout) as conn_err:
        print(f'bingo, ConnectionError, now lets wait {attempt * 10} seconds before retrying', (datetime.datetime.now()))
        time.sleep(attempt * 10)
        attempt = attempt + 1
        if attempt > 3:
            logging.error('Circuit-breaker forced exit')
            raise conn_err
    iterator = iterator + 1

Also try avoiding Python time.sleep() method in AWS Lambdas as this would not be cost efficient, AWS Step Functions would be much more appropriate.

Advertisements

Fibonacci sequence ( Python exercise )

Let’s continue with the simple Python exercises I’ve been messing around lately. This is a classical question at Dev job interviews, the Fibonacci sequence code. The idea behind this is to come up with code, that sums up the previous 2 member values for a member in the sequence, simply expressed like 1,2,3,5,8,13…

Below are my personal takes on this problem.

1: The nice and performing solution

#get fibonacci
import sys

def main(arg):
    seq_len = arg
    seq_len_iterator = 2
    var1 = 1
    var2 = 2
    fibonacci = ([var1, var2])

    while seq_len_iterator < seq_len:

        var3 = var1 + var2
        fibonacci.append(var3)

        i = len(fibonacci)
        var1 = fibonacci[i-2]
        var2 = fibonacci[i-1]

        seq_len_iterator = seq_len_iterator + 1

    print(f'Fibonacci sequence for {seq_len} sequence members goes like: {fibonacci}')

if __name__ == '__main__':
    try:
        arg = int(sys.argv[1])
        main(arg)
    except:
        print(f'Invalid input, must be integer!')

Execute with the needed sequence member count argument like for instance :

python.exe C:/codility/fibonacci/__main__.py 10

 

2: The alternative “nested-iterations” solution ( Not performing over ~30 sequence members count, durations exponentially grow, however its another example of a valid solution and can be useful if you need to warm oneself during long winter cold nights somewhere outside 🙂 )

#get fibonacci
import sys


def main(arg):
    seq_len = arg
    seq_len_iterator = 2
    iterator = 1
    var1 = 1
    var2 = 2
    fibonacci = ([var1, var2])

    while seq_len_iterator < seq_len:
        if iterator == var1 + var2:
            fibonacci.append(iterator)
            var1 = var2
            var2 = iterator
            iterator = iterator + 1
            seq_len_iterator = seq_len_iterator + 1
            #print(f'Fibonacci member found in try #: {iterator}')
        else:
            iterator = iterator + 1

    print(f'Fibonacci sequence for {seq_len} sequence members goes like: {fibonacci}')


if __name__ == '__main__':
    try:
        arg = int(sys.argv[1])
        main(arg)
    except:
        print(f'Invalid input, must be integer!')

Execute with the needed sequence member count argument like for instance :

python.exe C:/codility/fibonacci/__main__.py 10

Binary gap length ( Python exercise )

Sometimes I like to mess around http://www.codility.com , doing the excercises trying to keeping my development skills fresh. This is my take on the binary gap length problem using basic Python 3. The binary gap length is an excercise where you need to come up with a code, returning the longest sequence of zeros in a 16 digit “binary” string. This question also often shows up at developer job interviews.

#get max binary zeros gap
import re
import sys


def get_binary_gap(input_seq):
    iterator = 0
    iterator_zeros = '0'

    while iterator < 16:
        if iterator_zeros in input_seq:
            stack = len(iterator_zeros)
            if stack > iterator:
                output = stack

        elif iterator_zeros not in input_seq and len(iterator_zeros) == 1:
            output = 0

        else:
            pass

        iterator_zeros = iterator_zeros + '0'
        iterator = iterator + 1
    return output


def main(arg):
    input_seq = arg

    if len(input_seq) == 16 and bool(re.match("^[0-1]{1,16}$", input_seq)):
        output = get_binary_gap(input_seq)
        print(f'The max binary gap of zeros in sequence {input_seq} is {output}')

    else:
        print(f'invalid input sequence {input_seq}')


if __name__ == '__main__':
    arg = str(sys.argv[1])
    main(arg)

Execute with the binary sequence argument like for instance :

python.exe C:/codility/binary_gap/__main__.py 0100000101010100