Skip to content

Commit

Permalink
adding backoff to state saving in apps functions config
Browse files Browse the repository at this point in the history
  • Loading branch information
ryandeivert committed Apr 12, 2018
1 parent 6931ee1 commit 3051645
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 17 deletions.
41 changes: 25 additions & 16 deletions app_integrations/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import re
import time

import backoff
import boto3
from botocore.exceptions import ClientError

Expand All @@ -30,8 +31,10 @@
r'([2-9]+|[1-9]\d+) (minutes|hours|days))\)$')
AWS_RATE_HELPER = 'http://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html'


class AppConfig(dict):
"""Centralized config for handling configuration loading/parsing"""
MAX_SAVE_TRIES = 5
SSM_CLIENT = None

BASE_CONFIG_SUFFIX = 'config'
Expand Down Expand Up @@ -72,7 +75,14 @@ def __setitem__(self, key, value):

# If this is a key related to the state config, save the state in parameter store
if key in self._state_keys() and current_value != value:
self._save_state()
state_name = '_'.join([self['function_name'], self.STATE_CONFIG_SUFFIX])
param_value = json.dumps({key: self[key] for key in self._state_keys()})
try:
self._save_state(state_name, param_value)
except ClientError as err:
raise AppIntegrationStateError('Could not save current state to parameter '
'store with name \'{}\'. Response: '
'{}'.format(state_name, err.response))

@staticmethod
def remaining_ms():
Expand Down Expand Up @@ -292,26 +302,25 @@ def _determine_last_time(self):

return self.last_timestamp

def _save_state(self):
"""Function to save the value of this dictionary to parameter store
Raises:
AppIntegrationStateError: If state parameter cannot be saved, this is raised
"""
state_name = '_'.join([self['function_name'], self.STATE_CONFIG_SUFFIX])
param_value = json.dumps({key: self[key] for key in self._state_keys()})
try:
AppConfig.SSM_CLIENT.put_parameter(
Name=state_name,
def _save_state(self, param_name, param_value):
@backoff.on_exception(backoff.expo,
ClientError,
max_tries=self.MAX_SAVE_TRIES,
jitter=backoff.full_jitter)
def save():
"""Function to save the value of this dictionary to parameter store
Raises:
AppIntegrationStateError: If state parameter cannot be saved, this is raised
"""
self.SSM_CLIENT.put_parameter(
Name=param_name,
Description=self._STATE_DESCRIPTION.format(self['type'], self['app_name']),
Value=param_value,
Type='SecureString',
Overwrite=True
)
except ClientError as err:
raise AppIntegrationStateError('Could not save current state to parameter '
'store with name \'{}\'. Response: '
'{}'.format(state_name, err.response))
return save()

def _validate_config(self):
"""Validate the top level of the config to make sure it has all the right keys
Expand Down
2 changes: 1 addition & 1 deletion stream_alert_cli/manage_lambda/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ class AppIntegrationPackage(LambdaPackage):
package_files = {'app_integrations/__init__.py'}
package_name = 'stream_alert_app'
config_key = 'stream_alert_apps_config'
third_party_libs = {'boxsdk[jwt]==2.0.0a11', 'google-api-python-client', 'requests'}
third_party_libs = {'backoff', 'boxsdk[jwt]==2.0.0a11', 'google-api-python-client', 'requests'}
precompiled_libs = {'boxsdk[jwt]==2.0.0a11'}
version = apps_version

Expand Down
1 change: 1 addition & 0 deletions tests/unit/app_integrations/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
)


@patch.object(AppConfig, 'MAX_SAVE_TRIES', 1)
class TestAppIntegrationConfig(object):
"""Test class for AppIntegrationConfig"""

Expand Down

0 comments on commit 3051645

Please sign in to comment.