def check_availability_and_purchase(customer, event_sku, qty, tier="General"): """Check if there is sufficient inventory before making the purchase""" p = redis.pipeline() try: e_key = keynamehelper.create_key_name("event", event_sku) redis.watch(e_key) available = int(redis.hget(e_key, "available:" + tier)) price = float(redis.hget(e_key, "price:" + tier)) if available >= qty: p.hincrby(e_key, "available:" + tier, -qty) order_id = generate.order_id() purchase = { 'order_id': order_id, 'customer': customer, 'tier': tier, 'qty': qty, 'cost': qty * price, 'event_sku': event_sku, 'ts': long(time.time()) } so_key = keynamehelper.create_key_name("sales_order", order_id) p.hmset(so_key, purchase) p.execute() else: print "Insufficient inventory, have {}, requested {}".format( available, qty) except WatchError: print "Write Conflict check_availability_and_purchase: {}".format( e_key) finally: p.reset() print "Purchase complete!"
def reservation(event_sku, tier, block_name, first_seat, last_seat): """ Reserve the required seats. Create an expiring key (i.e. a latch) to reserve each seat. If that is successful, then an XOR can be executed to update the seat map, without needed a Watch.""" reserved = False p = redis.pipeline() try: for i in range(first_seat, last_seat + 1): # Reserve individual seat, raise exception is already reserved seat_key = keynamehelper.create_key_name("seatres", event_sku, tier, block_name, str(i)) if redis.set(seat_key, True, px=5000, nx=True) != True: raise SeatTaken(i, seat_key) order_id = generate.order_id() required_block = int(math.pow(2, last_seat - first_seat + 1)) - 1 << ( first_seat - 1) vals = ["SET", "u32", 0, required_block] res_key = keynamehelper.create_key_name("seatres", event_sku, tier, block_name, order_id) p.execute_command("BITFIELD", res_key, *vals) p.expire(res_key, 5) block_key = keynamehelper.create_key_name("seatmap", event_sku, tier, block_name) p.bitop("XOR", block_key, block_key, res_key) p.execute() reserved = True except SeatTaken as error: print "Seat Taken/{}".format(error.message) finally: p.reset() return reserved
def reserve(customer, event_sku, qty, tier="General"): """First reserve the inventory and perform a credit authorization. If successful then confirm the inventory deduction or back the deducation out.""" p = redis.pipeline() try: e_key = keynamehelper.create_key_name("event", event_sku) redis.watch(e_key) available = int(redis.hget(e_key, "available:" + tier)) if available >= qty: order_id = generate.order_id() ts = long(time.time()) price = float(redis.hget(e_key, "price:" + tier)) p.hincrby(e_key, "available:" + tier, -qty) p.hincrby(e_key, "held:" + tier, qty) # Create a hash to store the seat hold information hold_key = keynamehelper.create_key_name("ticket_hold", event_sku) p.hsetnx(hold_key, "qty:" + order_id, qty) p.hsetnx(hold_key, "tier:" + order_id, tier) p.hsetnx(hold_key, "ts:" + order_id, ts) p.execute() except WatchError: print "Write Conflict in reserve: {}".format(e_key) finally: p.reset() if creditcard_auth(customer, qty * price): try: purchase = { 'order_id': order_id, 'customer': customer, 'tier': tier, 'qty': qty, 'cost': qty * price, 'event_sku': event_sku, 'ts': long(time.time()) } redis.watch(e_key) # Remove the seat hold, since it is no longer needed p.hdel( hold_key, "qty:" + order_id, ) p.hdel(hold_key, "tier:" + order_id) p.hdel(hold_key, "ts:" + order_id) # Update the Event p.hincrby(e_key, "held:" + tier, -qty) # Post the Sales Order so_key = keynamehelper.create_key_name("sales_order", order_id) p.hmset(so_key, purchase) p.execute() except WatchError: print "Write Conflict in reserve: {}".format(e_key) finally: p.reset() print "Purchase complete!" else: print "Auth failure on order {} for customer {} ${}".format( order_id, customer, price * qty) backout_hold(event_sku, order_id)
def purchase(event_sku): """Simple purchase function, that pushes the sales order for publishing""" qty = random.randrange(1, 10) price = 20 order_id = generate.order_id() s_order = {'who': "Jim", 'qty': qty, 'cost': qty * price, 'order_id': order_id, 'event': event_sku, 'ts': generate.random_time_today()} post_purchases(order_id, s_order)
def create_purchase(self, customer, event, quantity): order_id = generate.order_id() purchase_key = keynamehelper.create_key_name("sales_order", order_id) purchase = {'state':'RESERVE', 'order_id': order_id, 'customer_id': customer['id'], 'qty': quantity, 'cost': quantity * float(event['price:General']), 'event_sku': event['sku'], 'ts': int(time.time())} self.redis.hmset(purchase_key, purchase) return purchase_key