VPC Peeringを使って、異なるVPCにあるRDSとEC2を接続する
VPC Peeringを使って、異なるVPCにあるRDSとEC2を接続する
VPC Peeringとは
VPC Peeringを設定する
VPC Peeringを作成する
EC2インスタンスから、同一アカウント、同一リージョン、異なるVPCにあるRDSへのアクセスを設定したいとする。
マネジメントコンソールからVPC設定を開いて、"Create Peering Connection"をクリック、項目を入力してVPC Peeringを作成する
項目 | 説明 |
---|---|
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(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(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/cache
をapp
コンテナとsidekiq
コンテナの両方が読み込もうとしてエラーが起きている様子。であれば、キャッシュフォルダをマウントしないか、bootsnapをsidekiq
コンテナでは使わないようにしてあげれば良さそうです
volumes: - .:/app /app/tmp/cache
CircleCIのorb namespaceをリネーム(あるいは削除)したい
TL;DR
表題について
namespace を作り間違えたので、リネーム方法を探したところ、ドキュメントに次の一文が:
Note: Namespaces cannot be removed or renamed once you have claimed a namespace.
コミュニティフォーラムでもnamespaceを削除したいという質問を発見したが、
There is no way to delete the namespace right now. We can rename a namespace if you open up a support ticket.
サポートに連絡してくれとの回答だったので、素直にここから連絡
すると、ものの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でリネーム可能になるかもしれん。
日本語でのサポートチケットにも対応してるらしいので、もし間違えて名前をつけてしまったら問い合わせてみよう。
コンポーネントのマウント時にリクエストし、アンマウント時にキャンセルする axios リクエスト
とりあえず解はこうなった。
ライブラリのバージョン
- axio 0.18.0
- react 16.8.3
- react-dom 16.8.3
動作確認はこちら:
ボタンクリックでコンポーネントのマウント・アンマウントが切り替えできる。APIリクエスト中にアンマウントされると、下のようなエラーメッセージと共にリクエストがキャンセルされる。
解説
解説というものでもないかもしれないが、ちょっと説明。
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.Up
は1
、Down
は2
、Left
は3
、Right
は4
となります。
また、初期値は省くこともできます。
enum Direction { Up, Down, Left, Right }
この場合、Up
は0
となり、Down
は1
となります。このオートインクリメントは、値自体は何でも良いが、同じ 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 メンバーへの参照 (他の enum でも可能)
- 括弧付きの定数 enum 式
+
、-
、~
の単項演算子が使われた定数 enum 式+
、-
、*
、/
、%
、<<
、>>
、>>>
、&
、|
、^
の二項演算子が使われた定数 enum 式。ただし、式の結果がNaN
かInfinity
の場合はコンパイルエラーとなります。
上記以外の場合、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'には適用できない } }
この例では、x
がE.Foo
ではないかどうかをチェックしています。このチェックがパスすれば、||
はスキップされて、if
文中が実行されます。しかし、前述のチェックがパスしなかった場合、x
はE.Foo
に限定されます。そのため、x
がE.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 メンバーは初期値を持たなければ、常に計算値としてみなされます。