def test_kill_device_multiple(): # If we kill a device and the folder has multiple devices, don't clear # the heartbeat status local_store = HeartbeatStore().store() proxy_for(1, 2, device_id=2).publish() proxy_for(1, 2, device_id=3).publish() clear_heartbeat_status(1, device_id=2) folders = local_store.get_account_folders(1) assert len(folders) == 1 f, ts = folders[0] assert f == '2'
def clear_heartbeat_status(account_id, folder_id=None, device_id=None, host=None, port=None): # Clears the status for the account, folder and/or device. # Returns the number of folders cleared. store = HeartbeatStore.store(host, port) n = store.remove_folders(account_id, folder_id, device_id) return n
def get_ping_status(host=None, port=6379, account_id=None, threshold=ALIVE_EXPIRY): # Query the indexes and not the per-folder info for faster lookup. store = HeartbeatStore.store(host, port) now = time.time() expiry = now - threshold if account_id: # Get a single account's heartbeat folder_heartbeats = store.get_account_folders(account_id) folders = [FolderPing(int(aid), ts > expiry, ts) for (aid, ts) in folder_heartbeats] account_ts = store.get_account_timestamp(account_id) account = AccountPing(account_id, account_ts > expiry, account_ts, folders) return {account_id: account} else: # Start from the account index account_heartbeats = store.get_account_list() accounts = {} # grab the folders from all accounts in one batch all_folder_heartbeats = store.get_accounts_folders( [aid for aid, ts in account_heartbeats]) for i, (account_id, account_ts) in enumerate(account_heartbeats): account_id = int(account_id) folder_heartbeats = all_folder_heartbeats[i] folders = [FolderPing(int(aid), ts > expiry, ts) for (aid, ts) in folder_heartbeats] account = AccountPing(account_id, account_ts > expiry, account_ts, folders) accounts[account_id] = account return accounts
def get_ping_status(account_ids, host=None, port=6379, threshold=ALIVE_EXPIRY): # Query the indexes and not the per-folder info for faster lookup. store = HeartbeatStore.store(host, port) now = time.time() expiry = now - threshold if len(account_ids) == 1: # Get a single account's heartbeat account_id = account_ids[0] folder_heartbeats = store.get_account_folders(account_id) folders = [FolderPing(int(aid), ts > expiry, ts) for (aid, ts) in folder_heartbeats] account = AccountPing(account_id, folders) return {account_id: account} else: accounts = {} # grab the folders from all accounts in one batch all_folder_heartbeats = store.get_accounts_folders(account_ids) for account_id in account_ids: account_id = int(account_id) folder_heartbeats = all_folder_heartbeats[account_id] folders = [FolderPing(int(aid), ts > expiry, ts) for (aid, ts) in folder_heartbeats] account = AccountPing(account_id, folders) accounts[account_id] = account return accounts
def get_account_metadata(host=None, port=6379, account_id=None): # Get account metadata (email, provider) from a folder entry. if not account_id: return store = HeartbeatStore.store(host, port) folder_id, folder_hb = store.get_single_folder(account_id) folder = FolderHeartbeatStatus(folder_id, load_folder_status(folder_id, folder_hb)) return (folder.email_address, folder.provider_name)
def store(monkeypatch): local_store = HeartbeatStore() @classmethod def scoped_store(*args, **kwargs): return local_store # Circumvent singleton behaviour for tests monkeypatch.setattr("inbox.heartbeat.store.HeartbeatStore.store", scoped_store) return HeartbeatStore.store()
def list_all_accounts(host=None, port=None, dead_threshold=ALIVE_EXPIRY, timestamps=False): # List all accounts with true/false heartbeats if alive or not. # If `timestamps` specified, returns (alive_or_not, timestamp) tuples. threshold = time.time() - dead_threshold store = HeartbeatStore.store(host, port) accounts = store.get_account_list() heartbeats = {} for (account, ts) in accounts: if timestamps: heartbeats[account] = (ts > threshold, ts) else: heartbeats[account] = ts > threshold return heartbeats
def list_alive_accounts(host=None, port=None, alive_since=ALIVE_EXPIRY, count=False, timestamps=False): # List accounts that have checked in during the last alive_since seconds. # Returns a list of account IDs. # If `count` is specified, returns count. # If `timestamps` specified, returns (account_id, timestamp) tuples. store = HeartbeatStore.store(host, port) if count: return store.count_accounts(alive_since) else: accounts = store.get_account_list(alive_since) if timestamps: return accounts return [a for a, ts in accounts]
def get_heartbeat_status(host=None, port=6379, account_id=None): # Gets the full (folder-by-folder) heartbeat status report for all # accounts or a specific account ID. store = HeartbeatStore.store(host, port) folders = store.get_folders(load_folder_status, account_id) accounts = {} for key, folder in folders.iteritems(): account = accounts.get(key.account_id, AccountHeartbeatStatus(key.account_id)) # Update accounts list by adding folder heartbeat. folder_hb = FolderHeartbeatStatus(key.folder_id, folder, ALIVE_THRESHOLD) account.add_folder(folder_hb) accounts[key.account_id] = account if account_id and account_id not in accounts: # If we asked about a specific folder and it didn't come back, # report it as missing. accounts[account_id] = AccountHeartbeatStatus(account_id, missing=True) return accounts
def list_dead_accounts(host=None, port=None, dead_threshold=ALIVE_EXPIRY, dead_since=None, count=False, timestamps=False): # List accounts that haven't checked in for dead_threshold seconds. # Optionally, provide dead_since to find accounts whose last # checkin time was after dead_since seconds ago. # Returns a list of account IDs. # If `count` is specified, returns count. # If `timestamps` specified, returns (account_id, timestamp) tuples. store = HeartbeatStore.store(host, port) if dead_since: if count: return store.count_accounts(dead_since, dead_threshold) else: accounts = store.get_accounts_between(dead_since, dead_threshold) else: if count: return store.count_accounts(dead_threshold, above=False) else: accounts = store.get_accounts_below(dead_threshold) if timestamps: return accounts return [a for a, ts in accounts]
def test_heartbeat_store_singleton(): # Test we don't unnecessarily create multiple instances of HeartbeatStore store_one = HeartbeatStore.store() store_two = HeartbeatStore.store() assert isinstance(store_one.client, MockRedis) assert id(store_one) == id(store_two)
def clear_heartbeat_status(account_id, folder_id=None, device_id=None): # Clears the status for the account, folder and/or device. # Returns the number of folders cleared. store = HeartbeatStore.store() n = store.remove_folders(account_id, folder_id, device_id) return n
def get_account_summary(host=None, port=6379, account_id=None): if not account_id: return [] store = HeartbeatStore.store(host, port) folders = store.get_account_folders(account_id) return folders
def get_account_timestamps(host=None, port=6379, account_id=None): store = HeartbeatStore.store(host, port) if account_id: return [(account_id, store.get_account_timestamp(account_id))] else: return store.get_account_list()
def get_timestamp(self): store = HeartbeatStore.store() store.get_account_timestamp(self.id)