VPC Peeringを使って、異なるVPCにあるRDSとEC2を接続する

VPC Peeringを使って、異なるVPCにあるRDSとEC2を接続する

VPC Peeringとは

  • プライベートIPアドレスを使って、2つのVPC間でトラフィックをルーティングすることができる
  • CIDRが一致または重複するVPC間の接続はできない

VPC Peeringを設定する

VPC Peeringを作成する

EC2インスタンスから、同一アカウント、同一リージョン、異なるVPCにあるRDSへのアクセスを設定したいとする。

マネジメントコンソールからVPC設定を開いて、"Create Peering Connection"をクリック、項目を入力してVPC Peeringを作成する

image

項目 説明
Peering connection name tag 識別名
VPC (Requester)* 接続元のVPC
Account 接続先のAWSアカウント
Region 接続先のAWSリージョン
VPC (Accepter)* 接続先のVPC

Routeを追加する

VPC Peering作成しただけではトラフィックのルートができないので、Route Tablesから、ルートを追加する。

接続元のVPC Route Table

Destination Target
(接続元のCIDRs) local
(接続先のCIDRs) (作成したVPC Peering) pcx-***

接続先のVPC Route Table

Destination Target
(接続先のCIDRs) local
(接続元のCIDRs) (作成したVPC Peering) pcx-***

Security Groupsを設定する

接続元のインスタンスから、接続先のRDSに対してincoming trafficを許可する。

Type Protocol Port Range Source
お好み TCP お好み 接続元のセキュリティグループ

VPC Peeringの設定が上手くいっていない場合、ここで「異なるVPC間のセキュリティグループは設定できない」旨のエラーが出る。

DNS解決を許可する

上記までの設定で、プライベートIPアドレスを用いればルーティングが可能になるが、RDSはプライベートIPアドレスが固定ではないため、ルーティングにはDNS名を使いたい。

なので作成したVPC Peeringの"Edit DNS Settings"からDNS resolutionを許可して、DNS名でアクセスできるようにする。

Palindrome Check (回文チェック) アルゴリズム

Palindrome Check (回文チェック) アルゴリズム

文字列stringを受け取って、回文かどうかをチェックする。すべての文字を比較しないといけないので、どうやっても計算量が$O(n)$以上になるはず。

アルゴリズム実装(1) $O(n)$

両端から文字が等しいか比較していく:

function isPalindrome(string) {
    let left = 0
    let right = string.length - 1
    let result = true
    while (left <= right) {
        if (string[left] === string[right]) {
            left++
            right--
        } else {
            result = false
            break
        }
    }
    
    return result
}

アルゴリズム実装(2) $O(n)$

文字の位置を反転させたreversedString文字列とstringの比較:

function isPalindrome(string) {
  const reversedString = []
    for (let i = string.length - 1; 0 <= i; i--) {
        reversedString.push(string[i])
    }
    
    return string === reversedString.join('')
}

フィボナッチ数列のアルゴリズム

フィボナッチ数列アルゴリズム

勉強がてらメモ

フィボナッチ数列とは

フィボナッチ数列」とは「前の2つの数を加えると次の数になる」という数列。1番目は0、2番目は1。n番目の数字は(n - 1)番目と(n - 2)番目の数字の和。

例えば、6番目の数は5 (0, 1, 1, 2, 3, 5)

アルゴリズム実装(1) O(n2)

n番目のフィボナッチ数をfib(n)とすれば、

fib(n) = fib(n - 1) + fib(n - 2)

fib(4)を求めるには

1                                  fib(4)
                     ________________|________________
                    |                                 |
2                  fib(3)                           fib(2)
            ________|________                 ________|________
           |                 |               |                 |
4         fib(2)           fib(1)          fib(1)            fib(0)
    ________|________
   |                 |
0 fib(1)           fib(0)

となるので、計算量はO(n^2)

1番目と2番めの例外に注意してこれを実装すると次のようになる:

function getFib(n) {
    if (n === 2) {
        return 1
    } else if (n === 1) {
        return 0
    }
    return getFib(n - 1) + getFib(n - 2)
} 

アルゴリズム実装(2) O(n)

先程の樹形図を見ると、fib(2)などすでに答えがでているものでも計算しているので、改善の余地があることに気づく。

一度出した答えを覚えておいて再利用できるならば、fib(4)の答えを得た時、例えばfib(6)を新たに求めたい場合は

fib(6) = fib(5) + fib(4)

であるが、fib(4)の答えはわかっているので、fib(5)だけを求めれば良い。同様にfib(n)を求めたい時、fib(n - 1)だけを求めれば良いから計算量はO(n)

これを実装するとき、fibStore配列にフィボナッチ数列を格納する。インデックスiの数字はfibStore[i - 1] + fibStore[i - 2]である。したがって

function getFib(n) {
    if (n === 2) {
        return 1
    } else if (n === 1) {
        return 0
    }

    const fibStore = [0, 1];
    
    for (let i = 2; i < n; i ++) {
        const ithFib = fibStore[i - 1] + fibStore[i - 2]
        fibStore[i] = ithFib
    }
    // n番目のフィボナッチ数 (インデックス n - 1)
    return fibStore[n - 1];
}

No such file or directory - bs_fetch:atomic_write_cache_file:chmod

No such file or directory - bs_fetch:atomic_write_cache_file:chmod

docker-composeを使ってサーバーとsidekiq両方を動かそうとすると次のようなエラーが出る場合があります:

$ docker-compose up
app_1          | [12] Puma starting in cluster mode...
app_1          | [12] * Version 4.1.0 (ruby 2.6.3-p62), codename: Fourth and One
app_1          | [12] * Min threads: 5, max threads: 5
app_1          | [12] * Environment: development
app_1          | [12] * Process workers: 2
app_1          | [12] * Preloading application
app_1          | [12] ! Unable to load application: Errno::ENOENT: No such file or directory - bs_fetch:atomic_write_cache_file:chmod
app_1          | bundler: failed to load command: puma (/usr/local/bundle/bin/puma)
app_1          | Errno::ENOENT: No such file or directory - bs_fetch:atomic_write_cache_file:chmod
app_1          |   /usr/local/bundle/gems/bootsnap-1.4.5/lib/bootsnap/compile_cache/iseq.rb:37:in `fetch'

簡略化しますが、docker-compose.ymlはだいたいこんなかんじ。appを2つのコンテナが共有している状態:

version: "3"
services:
  app:
    build: .
    command: bundle exec puma
    volumes:
      - .:/app
    ports:
      - "8080:8080"
    links:
      - redis
  sidekiq:
    build: .
    command: bundle exec sidekiq
    volumes:
      - .:/app
    links:
      - redis
  redis:
    image: redis
    volumes:
      - ./tmp/db:/var/lib/redis/data

おそらく、サーバーが立ち上がってからbootsnapで生み出されるapp/tmp/cacheappコンテナとsidekiqコンテナの両方が読み込もうとしてエラーが起きている様子。であれば、キャッシュフォルダをマウントしないか、bootsnapをsidekiqコンテナでは使わないようにしてあげれば良さそうです

    volumes:
      - .:/app
      /app/tmp/cache

CircleCIのorb namespaceをリネーム(あるいは削除)したい

TL;DR

  • 2019/03/20現時点ではnamespaceはCLIからリネームも削除もできない
  • ここからサポートに連絡すればすぐに対応してくれる

表題について

namespace を作り間違えたので、リネーム方法を探したところ、ドキュメントに次の一文が:

Note: Namespaces cannot be removed or renamed once you have claimed a namespace.

Creating Orbs - CircleCI

コミュニティフォーラムでもnamespaceを削除したいという質問を発見したが、

There is no way to delete the namespace right now. We can rename a namespace if you open up a support ticket.

How to delete orb namespace? - Orbs - CircleCI Discuss

サポートに連絡してくれとの回答だったので、素直にここから連絡

すると、ものの20分位でリネームに対応してくれた。

Hi Masato,

Currently namespace renames are only possible with assistance from Support. I've gone ahead and renamed the namespace to uraway for you, let me know if there are any issues!

"Currently"って言ってるので、もしかしたらこの先CLIでリネーム可能になるかもしれん。

日本語でのサポートチケットにも対応してるらしいので、もし間違えて名前をつけてしまったら問い合わせてみよう。

support.circleci.com

コンポーネントのマウント時にリクエストし、アンマウント時にキャンセルする axios リクエスト

とりあえず解はこうなった。

ライブラリのバージョン
  • axio 0.18.0
  • react 16.8.3
  • react-dom 16.8.3

動作確認はこちら:

ボタンクリックでコンポーネントのマウント・アンマウントが切り替えできる。APIリクエスト中にアンマウントされると、下のようなエラーメッセージと共にリクエストがキャンセルされる。

f:id:uraway:20190320135204p:plain

解説

解説というものでもないかもしれないが、ちょっと説明。

useEffectでマウント時のAPIリクエストのメソッドにキャンセルトークンソースを渡す。また、useEffectの戻り値はアンマウント時に実行されるので、ここでAPIリクエストのキャンセルを定義する。

function useAxios(fetchAction) {
  useEffect(() => {
    const signal = axios.CancelToken.source();
    fetchAction({ signal });
    return () => {
      signal.cancel("Api is being canceled");
    };
  }, []);
}

あとはaxiosにキャンセルトークンを渡すだけ:

  useAxios(({ signal }) => {
    async function getUser() {
      const res = await axios.get("https://randomuser.me/api/", {
        cancelToken: signal.token
      });
      setResult(res.data.results[0]);
    }

    getUser();
  });

react-routerとの組み合わせが便利なんじゃなかろうか。

TypeScript handbook Enums

TypeScript handbook Enums

https://www.typescriptlang.org/docs/handbook/enums.html

Enums

Enums

enums では、名前付きの定数群を定義します。その定数群の内容を明示したり、それぞれ異なるケースを簡単に作成することができます。TypeScript では、数値ベースと文字列ベースの enums を提供しています。

Numeric enums

まずは、他の言語でも馴染みのある数値 enums を見ていきます。enum キーワードを用いて定義します。

enum Direction {
  Up = 1,
  Down,
  Left,
  Right
}

ここでは、初期値1を持つUpの数値 enum を定義しています。それ以降のメンバーは自動的にインクリメントされるので、Direction.Up1Down2Left3Right4となります。

また、初期値は省くこともできます。

enum Direction {
  Up,
  Down,
  Left,
  Right
}

この場合、Up0となり、Down1となります。このオートインクリメントは、値自体は何でも良いが、同じ enum 内で値を区別するのに役立ちます。

enum の利用法はとてもシンプルです。プロパティにアクセスするように enum のメンバーにアクセスし、enum の名前を使って型を宣言するだけです。

enum Response {
  No = 0,
  Yes = 1
}

function respond(recipient: string, message: Response): void {
  // ...
}

respond("Princess Caroline", Response.Yes);

数値 enum は、計算値と定数を混在させることができます。つまり、初期値のない enum は最初か、数値定数や他の定数 enum のメンバーの初期値を持つ数値 enum の後ろでなければなりません。したがって次のようには宣言できません。

enum E {
  A = getSomeValue(),
  B // エラー! 'A' は定数で初期化されていないため、'B'には初期値が必要
}

String enums

文字列 enum も似たようなコンセプトですが、後述するように実行時のふるまいに少しだけ違いがあります。文字列 enum では、メンバーはそれぞれ文字列リテラルかあるいは他の文字列 enum メンバーを初期値として持たなければなりません。

enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

文字列 enum はオートインクリメントしませんが、そのかわりうまく"serialize"することができます。例えばデバッグで、数値 enum の実行中の値を読み取ろうとしても、その値自体には意味はない(リバースマッピングはしばしば役に立ちますが)ので困難ですが、文字列 enum であれば、実行中の値からもメンバーの名前以上の意味を汲み取れます。

Heterogeneous enums

必要性は低いですが、文字列 enum と数値 enum を混在させることは可能です。

enum BooleanLikeHeterogeneousEnum {
  No = 0,
  Yes = "YES"
}

JavaScript の実行中のふるまいをうまく利用しようとしているのでない場合は、おすすめしません。

Computed and constant members

enum メンバーはそれぞれ定数か計算値を持ちます。次のように定義した場合、enum メンバーは定数を持っているとみなされます。

  • enum の最初のメンバーが初期値を持たない場合

この場合メンバーの値は 0 となります。

// E.X は定数:
enum E {
  X
}
  • 初期値を持たず、かつ一つ前のメンバーが数値定数である場合。

この場合、メンバーの値は一つ前のメンバーの値に 1 を足した数値定数となります。

// 'E1' と 'E2' のすべてのメンバーは定数

enum E1 {
  X,
  Y,
  Z
}

enum E2 {
  A = 1,
  B,
  C
}
  • enum メンバーの初期値が定数 enum 式である場合

定数 enum 式とは、コンパイル時に評価可能な式のことで、次のような場合に当てはまります。

  1. リテラル enum 式 (基本的には文字列リテラルか数値リテラル)
  2. すでに定義した enum メンバーへの参照 (他の enum でも可能)
  3. 括弧付きの定数 enum
  4. +-~の単項演算子が使われた定数 enum
  5. +-*/%<<>>>>>&|^二項演算子が使われた定数 enum 式。ただし、式の結果がNaNInfinityの場合はコンパイルエラーとなります。

上記以外の場合、enum メンバーはすべて計算値としてみなされます。

enum FileAccess {
  // 定数メンバー
  None,
  Read = 1 << 1,
  Write = 1 << 2,
  ReadWrite = Read | Write,
  // 計算値メンバー
  G = "123".length
}

Union enums and enum member types

特殊な enum メンバーのひとつに、リテラル enum メンバーがあります。リテラル enum メンバーは、初期値を持たないか、あるいは、次のような初期値を持ちます。

すべてのメンバーがリテラル enum メンバーであるとき、いくつかの特殊な構文が使用できます。

ひとつめは、enum メンバーは型としても使用することができるようになります。たとえば、特定のメンバーは、enum メンバーの値だけを持つことができるというように定義することができます。

enum ShapeKind {
  Circle,
  Square
}

interface Circle {
  kind: ShapeKind.Circle;
  radius: number;
}

interface Square {
  kind: ShapeKind.Square;
  sideLength: number;
}

let c: Circle = {
  kind: ShapeKind.Square,
  //    ~~~~~~~~~~~~~~~~ エラー!
  radius: 100
};

また、enum 型はそれ自身がメンバーの union 型となります。union 型についてはまだ説明していませんが、union enums では、enum 自身に存在する値の集まりであること利用するということを知っておいてください。これにより、TypeScript は値を比較するときに起こしがちなささいなバグを防ぐことが可能になります。次の例を見てください。

enum E {
  Foo,
  Bar
}

function f(x: E) {
  if (x !== E.Foo || x !== E.Bar) {
    //             ~~~~~~~~~~~
    // エラー! '!=='オペレーターは'E.Foo'と'E.Bar'には適用できない
  }
}

この例では、xE.Fooではないかどうかをチェックしています。このチェックがパスすれば、||はスキップされて、if文中が実行されます。しかし、前述のチェックがパスしなかった場合、xE.Fooに限定されます。そのため、xE.Barであるかどうかを確認することは無駄ということになります。

Enums at runtime

enums は実行時にも存在する実オブジェクトです。例えば次の enum

enum E {
  X,
  Y,
  Z
}

実際に次の関数に渡すことができます。

function f(obj: { X: number }) {
  return obj.X;
}

// 'E'は数値のプロパティである'X'を持つため動作する
f(E);

Reverse mappings

enum はメンバーの名前と同じプロパティを持つオブジェクトを作成することに加えて、enum の値からその名前に対する reverse mapping も生成します。例えば、次のようなコードは

enum Enum {
  A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"

次のような JavaScriptコンパイルされます。

var Enum;
(function(Enum) {
  Enum[(Enum["A"] = 0)] = "A";
})(Enum || (Enum = {}));
var a = Enum.A;
var nameOfA = Enum[a]; // "A"

生成されたコードからは、enum は順方向(name -> value)と逆方向(value -> name)の両方のマッピングを持つオブジェクトにコンパイルされることがわかります。他の enum のメンバーへの参照は常にプロパティアクセスとして出力され、インラインされることはありません。

また、文字列 enum のメンバーは reverse mapping を生成しないことに注意してください。

const enums

ほとんどのケースでは、enums は有効な解決策ですが、より厳格な条件下で使用したいこともあるでしょう。余分に生成されるコードや enum の値へアクセスする間接的な参照のコストを避けるために、const enums を使用することができます。const enums はconst修飾子を enums につけて定義します。

const enum Enum {
  A = 1,
  B = A * 2
}

const enums は定数 enum 式にのみ用います。通常の enums とは異なり、コンパイル時に完全に取り除かれます。また、const enums メンバーはインラインされます。このために計算値を持ちません。

const enum Directions {
  Up,
  Down,
  Left,
  Right
}

let directions = [
  Directions.Up,
  Directions.Down,
  Directions.Left,
  Directions.Right
];

上記コードは、次のようにコンパイルされます。

var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

Ambient enums

ambient enums はすでにある enum 型を宣言するために使用します。

declare enum Enum {
  A = 1,
  B,
  C = 2
}

ambient と ambient ではない enums の大きな違いは、通常の enums では前のメンバーが定数であり、かつ、初期値を持たなければそのメンバーも定数とみなされるのに対して、ambient (const ではない) enum メンバーは初期値を持たなければ、常に計算値としてみなされます。