Usage and example of github actions matrix


Environment and Prerequisite

  • Github Actions


Background


Usage

  • According to the document, you can use it as shown below.
  • jobs.<job_id>.strategy.matrix is where you define the variables and values for the matrix.
  • In the example below, the values corresponding to version are [10, 12, 14] and the same applies to os.
jobs:
  example_matrix:
    strategy:
      matrix:
        version: [10, 12, 14]
        os: [ubuntu-latest, windows-latest]


Example

If you want to run Jekyll builds on multiple OS, you can write it as shown below. This is a workflow example actually used in this blog.

Code

  • This include other steps but just look on strategy in jobs’s build.
  • Define os on statement os: [ubuntu-22.04, ubuntu-20.04, macos-latest] and use it on runs-on: ${{ matrix.os }}.
  • The documentation states that if jobs.<job_id>.strategy.fail-fast is set to true or its expression evaluates to true, GitHub will cancel all in-progress and queued jobs in the matrix if any job in the matrix fails. To allow remaining jobs to continue even if one job fails, I’ve set this to false.
name: Jekyll Build CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:
    inputs:
      ruby-version:
        required: true
        type: string
        default: "3.2.2"
        
jobs:
  build:
    name: jekyll build
    strategy:
      matrix:
        os: [ubuntu-22.04, ubuntu-20.04, macos-latest]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v4
    - name: Setup Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: ${{ github.event.inputs.ruby-version }}
    - name: Install Bundler
      run: |
        gem install bundler
    - name: Install Dependencies
      run: |
        bundle install
    - name: Build Jekyll Site
      run: |
        bundle exec jekyll build

Result

  • To make it easier to understand, I’m attaching an image that shows the results of the execution.


Reference

PyYAML 사용 시 키 이름 “on”이 True로 바뀌는 사례


환경

  • Github Actions
  • Python
  • PyYAML


배경

  • Github Actions Workflow 파일을 동적으로 Python을 통해 수정하는데 YAML 파일 파싱시 on이라는 키가 True로 바뀌는 상황이 발생해서 정리.


예시

아래와 같이 Python에서 yaml을 통해 파일을 읽어서 출력하면 on이 사라지고 True가 들어가 있는걸 볼 수 있다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

결과

{'name': 'Workflow Complete Event Test', True: {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


이유

검색해보니 PyYAML의 경우 YAML 1.1 버전을 지원하고 있으며 1.1 버전의경우 "on"은 boolean으로 간주되며 그렇기에 True로 바뀌는게 맞다고 한다. YAML 1.2를 아직 지원하지 않다고 하기에 의도된 동작이며 방법을 따로 찾아야한다.


해결 방법

여러가지 방식이 있다.

  • Loader의 코드를 변경해서 설정
  • Key에 따옴표("" 또는 '')를 사용
  • 다른 Python 모듈 사용

따옴표가 눈에 띄어서 없애고 싶은 마음이 들지만 두번째 방식이 가장 간단해보이고 기존 yaml 모듈 변경이 없어서 해당 방식을 적용했다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

'on':
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

결과

{'name': 'Workflow Complete Event Test', 'on': {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


기타

True를 키 이름으로 사용

  • 키가 True로 잡히는데 Python에서 True를 사용하니 접근이 가능했다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content[True])

결과

{'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}


YAML 파일 생성 시 생성되는 키 이름

  • 여기서 yaml.dump를 통해 파일을 만들면 키는 true로 들어간다.

코드

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

with open('example.yaml', 'w') as file:
    yaml.dump(yaml_content, file)

결과

$ cat example.yaml
name: Workflow Complete Event Test
true:
  workflow_run:
    types:
    - completed
    workflows:
    - Push Main Branch
key:
  true: test


참고자료

Case of converting key name “on” to True when using PyYAML


Environment and Prerequisite

  • Github Actions
  • Python
  • PyYAML


Background

  • on key was automatically changed to True when modifying Github Actions Workflow file dynmically using Python.


Example

When reading and outputting a file using yaml in Python as shown below, you’ll notice that on is replaced with True.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

Result

{'name': 'Workflow Complete Event Test', True: {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


Reason

According to searching, PyYAML supports YAML 1.1 and in version 1.1, "on" is considered as a boolean value which is why it gets converted to True. Since YAML 1.2 is not yet supported, this behavior is intentional, and you will need to find an alternative solution.


Solution

There are many ways to solve it.

  • Modify Loader code
  • Use quote("" or '') to key
  • Use another Python module

Although I was tempted to remove the quotation marks, the second method seemed the simplest and didn’t require changes to the existing YAML module, so I applied that approach.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

'on':
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content)

Result

{'name': 'Workflow Complete Event Test', 'on': {'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}}


Others

Use True as key name

  • Key is set to True and it can be accessed via True in Python.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

print(yaml_content[True])

Result

{'workflow_run': {'workflows': ['Push Main Branch'], 'types': ['completed']}}


Key name after YAML file created

  • Key is set to true if make file via yaml.dump.

Code

import io
import yaml

file_content = """
name: Workflow Complete Event Test

on:
  workflow_run:
    workflows: [ "Push Main Branch" ]
    types:
      - completed
key:
  on: "test"
"""

file_like_object = io.StringIO(file_content)
yaml_content = yaml.safe_load(file_like_object)

with open('example.yaml', 'w') as file:
    yaml.dump(yaml_content, file)

Result

$ cat example.yaml
name: Workflow Complete Event Test
true:
  workflow_run:
    types:
    - completed
    workflows:
    - Push Main Branch
key:
  true: test


Reference

DynamoDB Throttling 발생 사례 정리


환경

  • AWS
  • DynamoDB


배경

  • DynamoDB 프로비저닝된 모드에서 Auto Scaling 사용 시 Throttling이 발생해서 이유를 조사해서 정리함.


이슈

  • DynamoDB 프로비저닝된 모드에서 Auto Scaling 설정을 사용했음에도 Throttling이 발생함.


이유

DynamoDB 관련 개념과 용어 정리

  • 내용을 정리하기 앞서서 몇 가지 개념과 용어가 새로 나와서 정리한다.

온디맨드 모드와 프로비저닝된 모드

  • 온디맨드 모드: 용량 계획 없이 초당 수백만 개의 요청을 처리할 수 있는 서버리스 청구 옵션으로 사용한만큼 지불하는 방식으로 보면 된다.
  • 프로비저닝된 모드: 애플리케이션에 필요한 초당 읽기 및 쓰기 횟수를 지정할 수 있으며 Auto Scaling을 사용하여 트래픽 변경에 따라 테이블의 프로비저닝된 용량을 자동으로 조정할 수 있다.
  • 관련 링크: https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/capacity-mode.html

WCU와 RCU

  • 프로비저닝된 용량 모드에서 애플리케이션에 필요한 초당 데이터 읽기 및 쓰기 단위이다.
  • WCU: 테이블에서 데이터를 쓰는 각 API 호출이 쓰기 요청이다.
  • RCU: 테이블에서 데이터를 읽는 각 API 호출이 읽기 요청이다.
  • 각 WCU 및 RCU에 대한 용량은 공식 문서에 나와있다.
  • 관련 링크: https://aws.amazon.com/ko/dynamodb/pricing/provisioned/

Auto Scaling

  • 위에 설명한 용량 단위의 최솟값 및 최댓값 그리고 목표 사용률 설정할 수 있다.
  • 목표 사용률에 따라 최솟값 및 최댓값 사이에서 용량을 조절한다. 간단하게 예를 들어 목표 사용률이 70% 이고 700 RCU를 사용한다면 1000 RCU를 프로비저닝 해둔다. 아래 정리하겠지만 남은 300 RCU를 패딩(Padding)이라 한다.
  • 관련 링크: https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/AutoScaling.html

패딩(Padding), 버스트 용량 그리고 Spike


Spike 발생 시 Throttling 발생 이유

  • 프로비저닝된 용량을 훨씬 넘어서는 Spike(갑작스러운 데이터 요청) 발생 시 아래와 같은 순서로 요청이 처리될 수 있다고 한다.
목표 사용률 이하 RCU 사용
-> 모든 RCU(목표 사용률 이하 RCU + Padding)를 통해 처리
-> 버스트 용량에서 처리
  • Spike에 대해 그래프에서와 같이 처음에는 버스트 용량에서 처리되다가 버스트 용량을 다 소진하면서 Throttling이 발생한다. 이후 Auto Scaling이 완료된 이후에는 Throttling이 사라진다.
  • 문서에 따르면 “Auto scaling triggers when your consumed capacity breaches the configured target utilization for two consecutive minutes. CloudWatch alarms might have a short delay of up to a few minutes before triggering auto scaling.”라고 나와있다.
  • DynamoDB의 경우 Auto Scaling이 일어나려면 CloudWatch에 1분간 연속해서 사용된 값이 목표 사용률을 넘어야 한다고 했다. 그렇기에 아래와 같은 이유로 지연이 생기게 되며 이게 순간적인 많은 요청에 대해 Throttling을 발생 시킨다.
    • CloudWatch에 표시되려면 약간의 시간 지연이 필요하다.
    • CloudWatch에 연속된 1분동안 목표 사용률을 넘는 상황이 발생하면 Auto Scaling을 시작한다.
    • Auto Scaling이 되는 과정에서 위에서 언급한 “목표 사용률 이하 RCU 사용 → 모든 RCU(목표 사용률 이하 RCU + Padding)를 통해 처리 → 버스트 용량에서 처리”를 넘어서는 요청에 대해서는 Throttling이 발생한다.
  • 관련 링크: https://aws.amazon.com/ko/blogs/database/handle-traffic-spikes-with-amazon-dynamodb-provisioned-capacity/
  • 관련 링크: https://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/AutoScaling.html


작가의 생각

  • Auto Scaling에서도 급격한 요청에 대해서는 Scaling을 탐지하는 부분과 조정하는 시간이 필요하기에 앞으로 설계시 이에 대한 고려도 하면 좋을거 같다.
  • 관련 조사를 진행하면서 DynamoDB Auto Scaling에 대해 많이 배웠다.
  • 예상하지 못한 급격한 트래픽 요청에 대해서는 알람이 오게 해야하며 트랙픽 증가가 예정된 부분이 있다면 점검하는 습관을 만들어야겠다.


참고자료

Post about case of DyanmoDb throttling


Environment and Prerequisite

  • AWS
  • DynamoDB


Background

  • Investigated and summarized the reasons for throttling when using auto scaling in DynamoDB provisioned mode.


Issue

  • Throttling occurs in DynamoDB even though auto scaling is set in provisioned mode.


Reason

  • Before summarize content, let me clarify some concepts and words.

On-demand capacity mode and Provisioned capacity mode

  • On-demand capacity mode: A serverless billing option that can serve millions of requests per second without capacity planning. Easily say pay what I used.
  • Provisioned capacity mode: Specify the number of reads and writes per second that you require for your application. We can use auto scaling to adjust your table’s provisioned capacity automatically in response to traffic changes.
  • Related Link: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/capacity-mode.html

WCU and RCU

  • Specify the number of data reads and writes per second that you require for your application. Unit of read and write in provisioned mode.
  • WCU: Each API call to write data to your table is a write request.
  • RCU: Each API call to read data from your table is a read request.
  • Each size of WCU and RCU is on official document.
  • Related Link: https://aws.amazon.com/dynamodb/pricing/provisioned/

Auto Scaling

  • We can set minimum, maximum provisioned capacity unit as mentioned in above and target utilization.
  • Capacity is controlled between minimum and maximun following to target utilization. For example if target utilization is 70% and use 700 RCU, then provisioned would be 1000 RCU. I will explain later but rest 300 RCU are called padding.
  • Related Link: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AutoScaling.html

Padding, Burst Capacity and Spike


Reason of Throttling When Spike Occurs

  • When a spike(sudden request traffic) exceeds the provisioned capacity, requests may be processed in the following order.
Use RCU under Target Utilization
-> Use All RCU(RCU under Target Utilization + Padding)
-> Use Burst Capacity
  • In spike, as shown in the above graph, firstly burst capacity handles requests and then throttling occures after use all prepared burst capacity. After auto scaling is done, then throttling disappears.
  • In document it says “Auto scaling triggers when your consumed capacity breaches the configured target utilization for two consecutive minutes. CloudWatch alarms might have a short delay of up to a few minutes before triggering auto scaling.”.
  • In DynamoDB auto scaling occurs when consumed capacity breaches the configured target utilization for two consecutive minutes. Therefore, delays occur for the following reasons, leading to throttling in reponse to spike in requests.
    • There is a short delay of up to CloudWatch.
    • Auto scaling will be started when consumed capacity breaches the configured target utilization for two consecutive minutes.
    • Throttling occurs in process of auto scaling over above “Use RCU under Target Utilization -> Use All RCU(RCU under Target Utilization + Padding) -> Use Burst Capacity” requests.
  • Related Link: https://aws.amazon.com/blogs/database/handle-traffic-spikes-with-amazon-dynamodb-provisioned-capacity/
  • Related Link: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AutoScaling.html


Author’s Thoughts

  • Due to scaling timing detection and setting time in auto scaling, it is good to consider about it when designing.
  • I learned many things about DynamoDB auto scaling.
  • Make alarm for unexpected sudden increase traffic. Make habit of review capacity when there is plan to have more traffic.


Reference