A bunch of interview stuff
This commit is contained in:
parent
9109a90e4b
commit
2bb3f9eada
123
dotfiles/lib/python/blackjack.py
Normal file
123
dotfiles/lib/python/blackjack.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import random
|
||||||
|
import enum
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
|
class Suit(enum.Enum):
|
||||||
|
CLUBS = 0
|
||||||
|
DIAMONDS = 1
|
||||||
|
HEARTS = 2
|
||||||
|
SPADES = 3
|
||||||
|
|
||||||
|
|
||||||
|
class Deck(object):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def random_deck(cls):
|
||||||
|
return cls(generate_cards())
|
||||||
|
|
||||||
|
def __init__(self, cards):
|
||||||
|
self._cards = cards
|
||||||
|
self.top = 0
|
||||||
|
|
||||||
|
def pop_top(self):
|
||||||
|
if self.top >= 52:
|
||||||
|
raise Exception()
|
||||||
|
card = get_card(self._cards[self.top])
|
||||||
|
self.top += 1
|
||||||
|
return card
|
||||||
|
|
||||||
|
|
||||||
|
def get_card(card_number):
|
||||||
|
return (Suit(card_number // 13), card_number % 13)
|
||||||
|
|
||||||
|
|
||||||
|
def random_permutation_of_size(n):
|
||||||
|
remaining = list(range(n))
|
||||||
|
for i in range(n-1, -1, -1):
|
||||||
|
yield remaining.pop(random.randint(0, i))
|
||||||
|
|
||||||
|
|
||||||
|
def random_permutation(the_list):
|
||||||
|
for index in random_permutation_of_size(len(the_list)):
|
||||||
|
yield the_list[index]
|
||||||
|
|
||||||
|
|
||||||
|
def generate_cards(num_cards=52):
|
||||||
|
return list(random_permutation(range(num_cards)))
|
||||||
|
|
||||||
|
|
||||||
|
def card_value(card_number):
|
||||||
|
if card_number >= 10:
|
||||||
|
return 10
|
||||||
|
return card_number + 1
|
||||||
|
|
||||||
|
|
||||||
|
def card_string(card_number):
|
||||||
|
if card_number == 12:
|
||||||
|
return 'K'
|
||||||
|
elif card_number == 11:
|
||||||
|
return 'Q'
|
||||||
|
elif card_number == 10:
|
||||||
|
return 'J'
|
||||||
|
return str(card_number + 1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_hand_value(hand):
|
||||||
|
number_of_aces = 0
|
||||||
|
total_value = 0
|
||||||
|
for _, card_number in hand:
|
||||||
|
if card_number == 0:
|
||||||
|
number_of_aces += 1
|
||||||
|
else:
|
||||||
|
total_value += card_value(card_number)
|
||||||
|
while total_value < 10 - (number_of_aces - 1):
|
||||||
|
total_value += 11
|
||||||
|
number_of_aces -= 1
|
||||||
|
total_value += number_aces
|
||||||
|
return total_value
|
||||||
|
|
||||||
|
|
||||||
|
class Blackjack(object):
|
||||||
|
|
||||||
|
def __init__(self, deck=None):
|
||||||
|
self._deck = deck or Deck.random_deck()
|
||||||
|
self.initialize_game()
|
||||||
|
|
||||||
|
def initialize_game(self):
|
||||||
|
self.dealer_hand = [self._deck.pop_top() for _ in range(2)]
|
||||||
|
self.player_hand = [self._deck.pop_top() for _ in range(2)]
|
||||||
|
|
||||||
|
def hit(self):
|
||||||
|
self.player_hand.append(self._deck.pop_top())
|
||||||
|
|
||||||
|
def run_dealer(self):
|
||||||
|
while get_hand_value(self.dealer_hand) < 17:
|
||||||
|
self.dealer_hand.append(self._deck.pop_top())
|
||||||
|
|
||||||
|
|
||||||
|
class UserHandler(object):
|
||||||
|
|
||||||
|
def __init__(self, game=None):
|
||||||
|
self._game = game or Blackjack()
|
||||||
|
|
||||||
|
def print_game_state(self):
|
||||||
|
print(self.game_string())
|
||||||
|
|
||||||
|
def game_string(self):
|
||||||
|
return "\n".join([
|
||||||
|
self.dealer_string(), self.hand_string(self._game.player_hand),
|
||||||
|
])
|
||||||
|
|
||||||
|
def dealer_string(self):
|
||||||
|
return "X {0}".format(self.hand_string(self._game.dealer_hand[1:]))
|
||||||
|
|
||||||
|
def hand_string(self, cards):
|
||||||
|
return " ".join(card_string(card[1]) for card in cards)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
UserHandler().print_game_state()
|
||||||
|
the_cards = UserHandler()._game._deck._cards
|
||||||
|
print (the_cards)
|
||||||
|
print(set(the_cards) == set(range(52)))
|
42
dotfiles/lib/python/crime_profit.py
Normal file
42
dotfiles/lib/python/crime_profit.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
class CountCrimes(object):
|
||||||
|
|
||||||
|
def __init__(self, profits, groups, profit_needed, group_count):
|
||||||
|
self.profits = profits
|
||||||
|
self.groups = groups
|
||||||
|
self.crime_count = len(profits)
|
||||||
|
self.profit_needed = profit_needed
|
||||||
|
self.group_count = count
|
||||||
|
self.reset_cache()
|
||||||
|
|
||||||
|
def process_crime(self, profit, num_required):
|
||||||
|
for gangster_count in range(self.group_count, -1, -1):
|
||||||
|
for profit_amount in range(self.profit_needed, -1, -1):
|
||||||
|
new_gangster_count = gangster_count + num_required
|
||||||
|
new_profit = profit_amount + profit
|
||||||
|
if new_profit > self.profit_needed:
|
||||||
|
new_profit = self.profit_needed
|
||||||
|
new_count = self.cache[gangster_count][profit_amount]
|
||||||
|
if new_count > 0 and new_gangster_count <= self.group_count:
|
||||||
|
self.cache[new_gangster_count][new_profit] += new_count
|
||||||
|
|
||||||
|
def reset_cache(self):
|
||||||
|
self.cache = [[0 for _ in range(profit_needed + 1)]
|
||||||
|
for _ in range(group_count + 1)]
|
||||||
|
self.cache[0][0] = 1
|
||||||
|
|
||||||
|
def process_crimes(self):
|
||||||
|
for profit, num_required in zip(self.profits, self.groups):
|
||||||
|
self.process_crime(profit, num_required)
|
||||||
|
|
||||||
|
def get_count(self):
|
||||||
|
self.reset_cache()
|
||||||
|
self.process_crimes()
|
||||||
|
return self.count_ways()
|
||||||
|
|
||||||
|
def count_ways(self):
|
||||||
|
return sum(self.cache[i][self.profit_needed]
|
||||||
|
for i in range(self.group_count + 1))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(CountCrimes().get_count())
|
58
dotfiles/lib/python/dashed_paragraph.py
Executable file
58
dotfiles/lib/python/dashed_paragraph.py
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
def textJustify(input_string, justification_length):
|
||||||
|
partitioning = partition_paragraph(input_string, justification_length)
|
||||||
|
return "\n".join(itertools.chain(
|
||||||
|
(justify_line(line_partition, justification_length)
|
||||||
|
for line_partition in partitioning[:-1]),
|
||||||
|
[" ".join(partitioning[-1])]
|
||||||
|
))
|
||||||
|
|
||||||
|
def justify_line(line_words, justification_length):
|
||||||
|
if len(line_words) == 1:
|
||||||
|
return line_words[0]
|
||||||
|
total_length = sum(len(word) for word in line_words)
|
||||||
|
word_count = len(line_words)
|
||||||
|
number_of_word_boundaries = word_count - 1
|
||||||
|
spaces_to_add = justification_length - total_length
|
||||||
|
base_spaces = spaces_to_add // number_of_word_boundaries
|
||||||
|
extra_spaces = spaces_to_add % number_of_word_boundaries
|
||||||
|
|
||||||
|
output_string = ""
|
||||||
|
for i, word in enumerate(line_words):
|
||||||
|
output_string += word
|
||||||
|
if i >= len(line_words) - 1:
|
||||||
|
break
|
||||||
|
space_count = base_spaces
|
||||||
|
if i < extra_spaces:
|
||||||
|
space_count += 1
|
||||||
|
spaces = " " * space_count
|
||||||
|
output_string += spaces
|
||||||
|
|
||||||
|
return output_string
|
||||||
|
|
||||||
|
def partition_paragraph(input_string, justification_length):
|
||||||
|
current_line_lenth = 0
|
||||||
|
partitioning = []
|
||||||
|
current = []
|
||||||
|
for word in input_string.split():
|
||||||
|
word_length = len(word)
|
||||||
|
length_with_word = current_line_lenth + word_length
|
||||||
|
if justification_length < length_with_word:
|
||||||
|
partitioning.append(current)
|
||||||
|
current = []
|
||||||
|
current_line_lenth = 0
|
||||||
|
length_with_word = word_length
|
||||||
|
|
||||||
|
current.append(word)
|
||||||
|
current_line_lenth = length_with_word + 1
|
||||||
|
|
||||||
|
if current:
|
||||||
|
partitioning.append(current)
|
||||||
|
|
||||||
|
return partitioning
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sample = "Coursera provides universal access to the world's best education, partnering with to universities and organizations to offer courses online."
|
||||||
|
print(textJustify(sample, 10))
|
107
dotfiles/lib/python/dialpad.py
Normal file
107
dotfiles/lib/python/dialpad.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# neighbors = {
|
||||||
|
# 1: [6, 8],
|
||||||
|
# 2: [7, 9],
|
||||||
|
# 3: [8, 4],
|
||||||
|
# 4: [9, 3, 0],
|
||||||
|
# 5: [],
|
||||||
|
# 6: [0, 7, 1],
|
||||||
|
# 7: [2, 6],
|
||||||
|
# 8: [1, 3],
|
||||||
|
# 9: [4, 2],
|
||||||
|
# 0: [4, 6]
|
||||||
|
# }
|
||||||
|
|
||||||
|
# cache = {}
|
||||||
|
|
||||||
|
# def count_numbers(current_number, number_of_hops):
|
||||||
|
# cache_value = (current_number, number_of_hops)
|
||||||
|
# if cache_value in cache:
|
||||||
|
# return cache[cache_value]
|
||||||
|
|
||||||
|
# if number_of_hops == 1:
|
||||||
|
# return 1
|
||||||
|
# number_count = 0
|
||||||
|
# for neighbor in neighbors[current_number]:
|
||||||
|
# number_count += count_numbers(neighbor, number_of_hops - 1)
|
||||||
|
|
||||||
|
# cache[cache_value] = number_count
|
||||||
|
# return number_count
|
||||||
|
|
||||||
|
|
||||||
|
class DialpadCounter(object):
|
||||||
|
|
||||||
|
knight_deltas = [
|
||||||
|
(2, 1),
|
||||||
|
(-2, -1),
|
||||||
|
(-2, 1),
|
||||||
|
(2, -1),
|
||||||
|
(1, 2),
|
||||||
|
(-1, -2),
|
||||||
|
(-1, 2),
|
||||||
|
(1, -2)
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, dialpad_matrix):
|
||||||
|
self._matrix = dialpad_matrix
|
||||||
|
self._row_size = len(dialpad_matrix[0])
|
||||||
|
self._row_count = len(dialpad_matrix)
|
||||||
|
self._cache = {}
|
||||||
|
|
||||||
|
def neighbors(self, y, x):
|
||||||
|
result = []
|
||||||
|
for delta_y, delta_x in self.knight_deltas:
|
||||||
|
neighbor_y = delta_y + y
|
||||||
|
neighbor_x = delta_x + x
|
||||||
|
neighbor = (neighbor_y, neighbor_x)
|
||||||
|
if (self.inbounds(neighbor_y, neighbor_x) and
|
||||||
|
self._matrix[neighbor_y][neighbor_x]):
|
||||||
|
result.append(neighbor)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def inbounds(self, y, x):
|
||||||
|
return 0 <= x < self._row_size and 0 <= y < self._row_count
|
||||||
|
|
||||||
|
def count_numbers(self, coordinate, number_of_hops):
|
||||||
|
y, x = coordinate
|
||||||
|
if not self._matrix[y][x]:
|
||||||
|
raise Exception()
|
||||||
|
|
||||||
|
cache_value = (coordinate, number_of_hops)
|
||||||
|
|
||||||
|
if cache_value in self._cache:
|
||||||
|
return self._cache[cache_value]
|
||||||
|
|
||||||
|
if number_of_hops == 1:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
number_count = 0
|
||||||
|
for neighbor in self.neighbors(y, x):
|
||||||
|
number_count += self.count_numbers(neighbor, number_of_hops - 1)
|
||||||
|
|
||||||
|
self._cache[cache_value] = number_count
|
||||||
|
|
||||||
|
return number_count
|
||||||
|
|
||||||
|
def count_numbers(number, number_of_hops):
|
||||||
|
matrix = [
|
||||||
|
[True, True, True],
|
||||||
|
[True, True, True],
|
||||||
|
[True, True, True],
|
||||||
|
[False, True, False]
|
||||||
|
]
|
||||||
|
if number == 0:
|
||||||
|
coordinate = 3, 1
|
||||||
|
else:
|
||||||
|
row = (number - 1) // 3
|
||||||
|
column = (number - 1) % 3
|
||||||
|
coordinate = (row, column)
|
||||||
|
counter = DialpadCounter(matrix)
|
||||||
|
return counter.count_numbers(coordinate, number_of_hops)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(count_numbers(1, 1))
|
||||||
|
print(count_numbers(1, 2))
|
||||||
|
print(count_numbers(1, 3))
|
||||||
|
print(count_numbers(1, 4))
|
||||||
|
print(count_numbers(1, 10))
|
||||||
|
print(count_numbers(1, 30))
|
56
dotfiles/lib/python/freenome.py
Normal file
56
dotfiles/lib/python/freenome.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
class MazeSolver(object):
|
||||||
|
|
||||||
|
def __init__(self, maze):
|
||||||
|
self.maze = maze
|
||||||
|
self.row_length = len(maze[0])
|
||||||
|
self.column_length = len(maze)
|
||||||
|
self.visited = set()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def finish(self):
|
||||||
|
return (self.column_length - 1, self.row_length - 1)
|
||||||
|
|
||||||
|
deltas = [(1, 0), (0, 1), (-1, 0), (0, -1)]
|
||||||
|
|
||||||
|
def is_in_bounds(self, location):
|
||||||
|
column_index, row_index = location
|
||||||
|
return (
|
||||||
|
0 <= column_index < self.column_length and
|
||||||
|
0 <= row_index < self.row_length
|
||||||
|
)
|
||||||
|
|
||||||
|
def find_adjacency(self, location):
|
||||||
|
for delta in self.deltas:
|
||||||
|
column_delta, row_delta = delta
|
||||||
|
column_location, row_location = location
|
||||||
|
new_column_location = column_location + column_delta
|
||||||
|
new_row_location = row_location + row_delta
|
||||||
|
adjacent_location = (new_column_location, new_row_location)
|
||||||
|
if (
|
||||||
|
self.is_in_bounds(adjacent_location) and
|
||||||
|
self.maze[new_column_location][new_row_location]
|
||||||
|
):
|
||||||
|
yield adjacent_location
|
||||||
|
|
||||||
|
def solve(self, current_location=(0, 0)):
|
||||||
|
if current_location == self.finish:
|
||||||
|
return [current_location]
|
||||||
|
self.visited.add(current_location)
|
||||||
|
for new_location in self.find_adjacency(current_location):
|
||||||
|
if new_location in self.visited:
|
||||||
|
continue
|
||||||
|
result = self.solve(new_location)
|
||||||
|
if result is not None:
|
||||||
|
return [current_location] + result
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
maze = [
|
||||||
|
[1, 1, 1, 1, 1],
|
||||||
|
[0, 0, 1, 0, 0],
|
||||||
|
[1, 0, 1, 1, 1],
|
||||||
|
[1, 0, 0, 0, 1],
|
||||||
|
[1, 1, 1, 1, 1]
|
||||||
|
]
|
||||||
|
|
||||||
|
print(MazeSolver(maze).solve())
|
85
dotfiles/lib/python/game_of_life.py
Executable file
85
dotfiles/lib/python/game_of_life.py
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
class GameOfLife(object):
|
||||||
|
|
||||||
|
neighbor_deltas = [
|
||||||
|
(1, 0), (1, 1), (1, -1),
|
||||||
|
(0, 1), (0, -1),
|
||||||
|
(-1, 0), (-1, 1), (-1, -1)
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def empty_with_size(cls, rows, columns=None):
|
||||||
|
columns = columns or rows
|
||||||
|
return cls([])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def build_empty_grid(rows, columns):
|
||||||
|
return [[False for _ in range(columns)] for _ in range(rows)]
|
||||||
|
|
||||||
|
def __init__(self, initial_state):
|
||||||
|
self.current_state = initial_state
|
||||||
|
self.row_count = len(initial_state)
|
||||||
|
self.column_count = len(initial_state[0])
|
||||||
|
|
||||||
|
def _neighbors(self, row, column):
|
||||||
|
for (row_delta, column_delta) in self.neighbor_deltas:
|
||||||
|
candidate_row = row + row_delta
|
||||||
|
candidate_column = column + column_delta
|
||||||
|
if self._in_bounds(candidate_row, candidate_column):
|
||||||
|
yield candidate_row, candidate_column
|
||||||
|
|
||||||
|
def _in_bounds(self, row, column):
|
||||||
|
return 0 <= row < self.row_count and 0 <= column < self.column_count
|
||||||
|
|
||||||
|
def _next_state_for_cell(self, row, column):
|
||||||
|
live_count = 0
|
||||||
|
cell_was_live = self.current_state[row][column]
|
||||||
|
for neighbor_row, neighbor_column in self._neighbors(row, column):
|
||||||
|
if self.current_state[neighbor_row][neighbor_column]:
|
||||||
|
live_count += 1
|
||||||
|
if cell_was_live:
|
||||||
|
return 1 < live_count < 4
|
||||||
|
else:
|
||||||
|
return live_count == 3
|
||||||
|
|
||||||
|
def compute_next_game_state(self, new_state=None):
|
||||||
|
new_state = new_state or self.build_empty_grid(
|
||||||
|
self.row_count, self.column_count,
|
||||||
|
)
|
||||||
|
for row in range(self.row_count):
|
||||||
|
for column in range(self.column_count):
|
||||||
|
new_state[row][column] = self._next_state_for_cell(row, column)
|
||||||
|
return new_state
|
||||||
|
|
||||||
|
def tick(self, new_state=None):
|
||||||
|
self.current_state = self.compute_next_game_state(new_state)
|
||||||
|
|
||||||
|
def _build_row_string(self, row):
|
||||||
|
return " ".join(["o" if state else "." for state in row])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state_string(self):
|
||||||
|
return "\n".join(
|
||||||
|
self._build_row_string(row) for row in self.current_state
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls, initial_state, generations=30):
|
||||||
|
game = cls(initial_state)
|
||||||
|
for _ in range(generations):
|
||||||
|
game.tick()
|
||||||
|
print(game.state_string)
|
||||||
|
return game.current_state
|
||||||
|
|
||||||
|
sample_size = 50
|
||||||
|
|
||||||
|
sample_state = [
|
||||||
|
[False, True, False] + ([False] * (sample_size - 3)),
|
||||||
|
[False, False, True] + ([False] * (sample_size - 3)),
|
||||||
|
[True, True, True] + ([False] * (sample_size - 3)),
|
||||||
|
] + [[False] * sample_size for _ in range(sample_size - 3)]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
GameOfLife.run(sample_state)
|
58
dotfiles/lib/python/justify_paragraph.py
Executable file
58
dotfiles/lib/python/justify_paragraph.py
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
def textJustify(input_string, justification_length):
|
||||||
|
partitioning = partition_paragraph(input_string, justification_length)
|
||||||
|
return "\n".join(itertools.chain(
|
||||||
|
(justify_line(line_partition, justification_length)
|
||||||
|
for line_partition in partitioning[:-1]),
|
||||||
|
[" ".join(partitioning[-1])]
|
||||||
|
))
|
||||||
|
|
||||||
|
def justify_line(line_words, justification_length):
|
||||||
|
if len(line_words) == 1:
|
||||||
|
return line_words[0]
|
||||||
|
total_length = sum(len(word) for word in line_words)
|
||||||
|
word_count = len(line_words)
|
||||||
|
number_of_word_boundaries = word_count - 1
|
||||||
|
spaces_to_add = justification_length - total_length
|
||||||
|
base_spaces = spaces_to_add // number_of_word_boundaries
|
||||||
|
extra_spaces = spaces_to_add % number_of_word_boundaries
|
||||||
|
|
||||||
|
output_string = ""
|
||||||
|
for i, word in enumerate(line_words):
|
||||||
|
output_string += word
|
||||||
|
if i >= len(line_words) - 1:
|
||||||
|
break
|
||||||
|
space_count = base_spaces
|
||||||
|
if i < extra_spaces:
|
||||||
|
space_count += 1
|
||||||
|
spaces = " " * space_count
|
||||||
|
output_string += spaces
|
||||||
|
|
||||||
|
return output_string
|
||||||
|
|
||||||
|
def partition_paragraph(input_string, justification_length):
|
||||||
|
min_line_length = 0
|
||||||
|
partitioning = []
|
||||||
|
current = []
|
||||||
|
for word in input_string.split():
|
||||||
|
word_length = len(word)
|
||||||
|
length_with_word = min_line_length + word_length
|
||||||
|
if justification_length < length_with_word:
|
||||||
|
partitioning.append(current)
|
||||||
|
current = []
|
||||||
|
min_line_length = 0
|
||||||
|
length_with_word = word_length
|
||||||
|
|
||||||
|
current.append(word)
|
||||||
|
min_line_length = length_with_word + 1
|
||||||
|
|
||||||
|
if current:
|
||||||
|
partitioning.append(current)
|
||||||
|
|
||||||
|
return partitioning
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sample = "Coursera provides universal access to the world's best education, partnering with to universities and organizations to offer courses online."
|
||||||
|
print(textJustify(sample, 10))
|
62
dotfiles/lib/python/webhook.py
Normal file
62
dotfiles/lib/python/webhook.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import asyncio
|
||||||
|
import random
|
||||||
|
import queue
|
||||||
|
import requests
|
||||||
|
import threading
|
||||||
|
|
||||||
|
class WebhookHandler(object):
|
||||||
|
|
||||||
|
def __init__(self, callback_uri='http://whatever'):
|
||||||
|
self.queue = queue.Queue()
|
||||||
|
self.callback_uri = callback_uri
|
||||||
|
|
||||||
|
def enqueue(self, webhook_request):
|
||||||
|
self.queue.put(webhook_request)
|
||||||
|
|
||||||
|
def webhook_worker(self):
|
||||||
|
while True:
|
||||||
|
callback_request = self.queue.get()
|
||||||
|
self.run_request(callback_request)
|
||||||
|
self.queue.task_done()
|
||||||
|
|
||||||
|
def flaky_request(self, callback_request):
|
||||||
|
random_value = random.random()
|
||||||
|
print(random_value)
|
||||||
|
if random_value > .9:
|
||||||
|
return 500
|
||||||
|
r = requests.get(self.callback_uri, params=callback_request)
|
||||||
|
return r.status_code
|
||||||
|
|
||||||
|
def run_request(self, request):
|
||||||
|
status_code = self.flaky_request(request)
|
||||||
|
if status_code != 200:
|
||||||
|
asyncio.run(self.do_retry(callback_request))
|
||||||
|
else:
|
||||||
|
print("made request")
|
||||||
|
|
||||||
|
async def do_retry(self, request, delay=1):
|
||||||
|
await asyncio.sleep(delay)
|
||||||
|
print("Retried request")
|
||||||
|
self.run_request(request)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
handler = WebhookHandler(callback_uri="https://www.google.com/")
|
||||||
|
thread_count = 10
|
||||||
|
for _ in range(1000):
|
||||||
|
handler.enqueue({})
|
||||||
|
|
||||||
|
threads = []
|
||||||
|
for _ in range(thread_count):
|
||||||
|
thread = threading.Thread(target=handler.webhook_worker, daemon=False)
|
||||||
|
thread.start()
|
||||||
|
threads.append(thread)
|
||||||
|
|
||||||
|
for _ in range(1000):
|
||||||
|
handler.enqueue({})
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
try:
|
||||||
|
loop.run_forever()
|
||||||
|
finally:
|
||||||
|
loop.close()
|
Loading…
Reference in New Issue
Block a user