[AWS] Boto3 rds.describe_events의 StartTime, EndTime 경계값 포함여부

boto3를 이용해서 AWS API 다룰일이 많은데, 이번에 작업을 하다보니 API문서에 명시되지 않은 내용이 있어서 공유하고자 몇 자 적어본다.

TLDR; Boto3 API에서 StartTime, EndTime형태의 시간 범위 지정 파라미터를 사용하는 경우 StartTime = Inclusive, EndTime = Exclusive로 작동한다. StartTime <= Datetime of data < EndTime.
그리고 가장 작은 비교 단위는 1,000 마이크로세컨즈 이다.

RDS의 describe_events API는 RDS 서비스들에서 발생한 Event를 불러오는 API이다.

response = client.describe_events(
    SourceIdentifier='string',
    SourceType='db-instance'|'db-parameter-group'|'db-security-group'|'db-snapshot'|'db-cluster'|'db-cluster-snapshot'|'custom-engine-version'|'db-proxy',
    StartTime=datetime(2015, 1, 1),
    EndTime=datetime(2015, 1, 1),
    Duration=123,
    EventCategories=[
        'string',
    ],
    Filters=[
        {
            'Name': 'string',
            'Values': [
                'string',
            ]
        },
    ],
    MaxRecords=123,
    Marker='string'
)

request syntax는 다음과 같은데, SourceType을 지정함으로써 여러 종류 리소스들의 Event를 받아오는 API이다.

API를 쓰면서 Parameter중 아래 파라미터들에 대해서 굉장히 설명이 부족하다고 느꼈는데, 특히 StartTime과 EndTime이 Inclusive한지에 대한 것이었다. -> RDS API 문서에는 일절 설명이 없다.

  • StartTime (datetime) –The beginning of the time interval to retrieve events for, specified in ISO 8601 format. For more information about ISO 8601, go to the ISO8601 Wikipedia page.Example: 2009-07-08T18:00Z
  • EndTime (datetime) –The end of the time interval for which to retrieve events, specified in ISO 8601 format. For more information about ISO 8601, go to the ISO8601 Wikipedia page.Example: 2009-07-08T18:00Z
https://boto3.amazonaws.com/v1/documentation/api/1.20.44/reference/services/rds.html#RDS.Client.describe_events


그래서 일단은 StartTime과 EndTime 모두 Inclusive 하다는 가정을 하고 API개발을 진행을 했었다.
사실 테스트 해볼 생각을 못했는데, 최근에 CloudWatch API를 사용하면서 비슷한 구조를 가진 API를 사용하게 되면서 테스트를 해보았다.

아래는 get_metric_statistics API의 파라미터 설명중 일부이다.

  • StartTime (datetime) –[REQUIRED]The time stamp that determines the first data point to return. Start times are evaluated relative to the time that CloudWatch receives the request.The value specified is inclusive; results include data points with the specified time stamp. In a raw HTTP query, the time stamp must be in ISO 8601 UTC format (for example, 2016-10-03T23:00:00Z).CloudWatch rounds the specified time stamp as follows:
    • Start time less than 15 days ago – Round down to the nearest whole minute. For example, 12:32:34 is rounded down to 12:32:00.
    • Start time between 15 and 63 days ago – Round down to the nearest 5-minute clock interval. For example, 12:32:34 is rounded down to 12:30:00.
    • Start time greater than 63 days ago – Round down to the nearest 1-hour clock interval. For example, 12:32:34 is rounded down to 12:00:00.
    If you set Period to 5, 10, or 30, the start time of your request is rounded down to the nearest time that corresponds to even 5-, 10-, or 30-second divisions of a minute. For example, if you make a query at (HH:mm:ss) 01:05:23 for the previous 10-second period, the start time of your request is rounded down and you receive data from 01:05:10 to 01:05:20. If you make a query at 15:07:17 for the previous 5 minutes of data, using a period of 5 seconds, you receive data timestamped between 15:02:15 and 15:07:15.
  • EndTime (datetime) –[REQUIRED]The time stamp that determines the last data point to return.The value specified is exclusive; results include data points up to the specified time stamp. In a raw HTTP query, the time stamp must be in ISO 8601 UTC format (for example, 2016-10-10T23:00:00Z).

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudwatch/client/get_metric_statistics.html

CW API에서느 친절하게 StartTime, EndTime에 대해서 Exclusive, Inclusive여부를 설명해준다.
타임스탬프를 2023-04-24T04:00:00Z,로 지정한다면 결과는 2023-04-24T03:59:59Z, 까지만의 데이터만 보여준다는 것이다.

그래서 다시 돌아와서 RDS API도 비슷하게 동작하지 않을까 라는 가정을 가지고 테스트를 해보았다.

미리 API를 이용해서 datetime(2023, 4, 12, 16, 0, 35, 682000) 시간에 이벤트가 하나 있는 걸 확인했다.
아래 4가지 케이스로 테스트를 해보았다.

case 1. 681000/682000 오른쪽 경계값에 포함되는지
case 2. 682000/683000 왼쪽 경계값에 포함되는지
case 3. 682000/682001 1 마이크로 세컨드도 인식하는지
case 4. 682000/682999 999마이크로 세컨드도 인식하는지

# case 1
start_time_window = datetime(2023, 4, 12, 16, 0, 35, 681000)
end_time_window = datetime(2023, 4, 12, 16, 0, 35, 682000)
rds_events = rds.describe_events(resource_id, RDSEventSourceType.CLUSTER,
                                 start_time=start_time_window, end_time=end_time_window)['Events']
print('case 1', len(rds_events))

# case 2
start_time_window = datetime(2023, 4, 12, 16, 0, 35, 682000)
end_time_window = datetime(2023, 4, 12, 16, 0, 35, 683000)
rds_events = rds.describe_events(resource_id, RDSEventSourceType.CLUSTER,
                                 start_time=start_time_window, end_time=end_time_window)['Events']
print('case 2', len(rds_events))


# case 3
start_time_window = datetime(2023, 4, 12, 16, 0, 35, 682000)
end_time_window = datetime(2023, 4, 12, 16, 0, 35, 682001)
rds_events = rds.describe_events(resource_id, RDSEventSourceType.CLUSTER,
                                 start_time=start_time_window, end_time=end_time_window)['Events']
print('case 3', len(rds_events))

# case 4
start_time_window = datetime(2023, 4, 12, 16, 0, 35, 682000)
end_time_window = datetime(2023, 4, 12, 16, 0, 35, 682999)
rds_events = rds.describe_events(resource_id, RDSEventSourceType.CLUSTER,
                                 start_time=start_time_window, end_time=end_time_window)['Events']
print('case 4', len(rds_events))

# case 4
start_time_window = datetime(2023, 4, 12, 16, 0, 35, 682000)
end_time_window = datetime(2023, 4, 12, 16, 0, 35, 682000)
rds_events = rds.describe_events(resource_id, RDSEventSourceType.CLUSTER,
                                 start_time=start_time_window, end_time=end_time_window)['Events']
print('case 4', len(rds_events))

>> python test_timewindow.py
case 1 0
case 2 1
case 3 0
case 4 0

결국 case 2 번에서만 정상적으로 이벤트가 출력이 되었다.
결국 왼쪽값만 포함, 오른쪽 값은 불포함이 된다.

10분마다 해당 이벤트를 불러오는 크론잡을 설계하면서, Time Window가 중복되지 않도록 설계를 하려다보니 값의 포함여부가 중요했는데, 이번 테스트로 설계의 확신을 얻을 수 있었다.