Source code for lambdas.storepick_colleague_handler
import json
import sys
import time
from datetime import datetime, timedelta
import logging
from pymorri.exceptions import MoriException
from pymorri.util.datadog_utils import post_datadog_event_to_sns
from pymorri.util.response_builder import ResponseBuilder
from pymorri.api.morrisons.colleague import QueryColleagues
from pymorri.api.morrisons.colleaguediscount import DeleteColleagueDiscount
from pymorri.util.application_dependencies import ApplicationDependencies
from pymorri.util.general_utils import build_response_or_throw
from pymorri.util.gcp_clients import GCPStorageClient
from constants import APP_NAME, SSM_NAME, DATADOG_APP_NAME, DD_CHECK_METRIC_NAME
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
DEFAULT_TIMEOUT = 60
[docs]@build_response_or_throw
def lambda_handler(event, context):
"""
This Lambda queries customer lists of leavers since yesterday and delete them
using DELETE endpoint of colleague discount api (DELETE /colleaguediscount/v1/colleagues)
Input:
- event (dict) - can be empty json {} but CANNOT be None
Output:
- resp (dict): HTTP response - 200 on success and 500 on failure / exception
Additionally function post CHECK status to DataDog API:
- metric name: `colleague_discount_check`
- app name: `storepick_colleague_discount`
It sends:
* value 0 (SUCCESS) when this function returns 200
* value 2 (ERROR) when this function throws exception
+ exception is handled and processed in `build_response_or_throw` decorator
and error response with 500 or 4xx is sent.
Example body:
.. code-block:: python
resp = {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
'body': {
"status": "success",
"message": "Today colleage leavers deleted successfully",
"body": []
}
}
Raises:
MoriException: MoriException for timeout of retrieving file from QueryColleagues endpoint
"""
#update event in order this function could send STATUS data to DataDog API
#from build_response_or_throw
event.update({
"DATADOG_APP_NAME": DATADOG_APP_NAME,
"DD_CHECK_METRIC_NAME": DD_CHECK_METRIC_NAME,
})
all_leavers = []
successful_leavers_number = 0
failed_leavers_number = 0
deps = ApplicationDependencies(config_file=f"{APP_NAME}.json", ssm_param_store_name=SSM_NAME)
timeout = int(deps.get_config().get("GET_COLLEAGE_JOB_ID_PROCESSING_TIMEOUT", DEFAULT_TIMEOUT))
scope = deps.get_config().get("QUERYCOLLEAGUES_SCOPE_VALUE", "LEAVER")
today = datetime.today().strftime("%Y-%m-%d")
query = QueryColleagues(ssm=deps.get_ssm_params(), configuration=deps.get_config())
resp = query.request(scope=scope, from_date=today, to_date=today)
logger.info(f"QueryColleagues - resp: {resp}")
job_id = resp.get("payload").get("jobId")
logger.info(f"Retrieved job_id {job_id} from query GET /colleague endpoint "
f"with params: scope: {scope}, from_date: {today}; to_date: {today}")
status = "UNKNOWN"
try_number = 0
start_time = datetime.now()
#will be break when status == COMPLETED or when timeout occurs
while True:
end_time = datetime.now()
try_number += 1
resp = query.request(job_id=job_id)
payload = resp.get("payload")
if payload:
status = str(payload.get("status"))
logger.info(f"Checking whether job_id {job_id} processing finished "
f"- try_number: {try_number}. Resp: {resp}")
if (end_time - start_time).total_seconds() > timeout:
message = f"TIMEOUT of {timeout} seconds reached while processing job_id: {job_id}"
logger.error(message)
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="check",
metric_name=DD_CHECK_METRIC_NAME, metric_value="2")
raise MoriException(http_status_code=500, detail=message)
if status == "COMPLETED":
break
#sleep 5 seconds between each request
time.sleep(5)
resp_file = payload.get("file").split("gs://")[1]
bucket_name = resp_file.split("/")[0]
file_path = resp_file.split(f"{bucket_name}/")[1]
all_leavers = GCPStorageClient(SSM_NAME).get_file_content(
bucket_name,
file_path,
base64_encryption_key=deps.get_ssm_params().get("DECRYPTION_KEY") if deps.get_ssm_params().get(
"DECRYPTION_KEY") and len(deps.get_ssm_params().get("DECRYPTION_KEY")) > 0 else None
)
logger.info(f"Number of leavers to process: {len(all_leavers)}")
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="count",
metric_name="leavers_retrieved", metric_value=len(all_leavers))
delete_obj = DeleteColleagueDiscount(ssm=deps.get_ssm_params(), configuration=deps.get_config())
for leaver in all_leavers:
employee_id = str(leaver.get("employeeId"))
try:
_ = delete_obj.request(employee_id)
successful_leavers_number += 1
except MoriException as ex:
failed_leavers_number += 1
if ex.http_status_code == 404:
logger.warning(f"Customer NOT FOUND while DeleteColleague {employee_id} from API: {ex}")
else:
logger.error(f"EXCEPTION while DeleteColleague {employee_id} from API: {ex}")
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="count",
metric_name="leavers_success", metric_value=successful_leavers_number)
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="count",
metric_name="leavers_failed", metric_value=failed_leavers_number)
if failed_leavers_number == 0:
event['response_message'] = "All today colleague leavers deleted successfully"
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="check",
metric_name=DD_CHECK_METRIC_NAME, metric_value="0")
logger.info(f"All today colleague leavers deleted")
else:
event['response_message'] = f"{successful_leavers_number}/{len(all_leavers)} today colleague leavers deleted"
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="check",
metric_name=DD_CHECK_METRIC_NAME, metric_value="1")
logger.warning(f"{successful_leavers_number}/{len(all_leavers)} today colleague leavers deleted")
return event
if __name__ == "__main__":
event = {}
response = lambda_handler(event, None)
logger.info(f"{response}")