- 投稿日:2020-06-04T23:39:25+09:00
自動売買のbitflyer.comでHTTP API使ってみたよ?
自動売買のbitflyer.comでHTTP API使ってみたよ。?
使ってみて思ったことはリアルタイム処理とHTTP APIを混合で
使うべしだと・・・。ただ・・ビットコインの価格高いよね。
私には買えない。http_api.js//板情報 var F = require('./api-bitflyer.com.js'); F.Fapi.init.key = "APIKEY"; F.Fapi.init.secret = "secretkey"; F.Fapi.init.method = "GET"; F.Fapi.init.path = "/v1/getboard"; F.Fapi.init.data = { "product_code": "ETH_JPY" }; F.Fapi.run();api-bitflyer.com.jsexports.Fapi = { init: { key: "", secret: "", method: "", path: "", data: "" }, run: function () { var request = require('request'); var crypto = require('crypto'); var timestamp = Date.now().toString(); var method = this.init.method; var path = this.init.path; var body = JSON.stringify( this.init.data ); var text = timestamp + method + path + body; var sign = crypto.createHmac('sha256', this.init.secret).update(text).digest('hex'); var pra = function(data){ let str = []; for (const key in data) { if (data.hasOwnProperty(key)) { str.push(key + "=" + data[key]); } } return "?" + str.join('&'); }; var options = { url: 'https://api.bitflyer.com' + path + (method.toUpperCase()==="POST"?"":pra(this.init.data)), method: method, body: body, headers: { 'ACCESS-KEY': this.init.key, 'ACCESS-TIMESTAMP': timestamp, 'ACCESS-SIGN': sign, 'Content-Type': 'application/json' } }; request(options, function (err, response, retload) { console.log(retload); }); } };
- 投稿日:2020-06-04T23:39:25+09:00
自動売買☓bitflyer.comでHTTP API使ってみたよ?
自動売買☓bitflyer.comでHTTP API使ってみたよ。?
使ってみて思ったことはリアルタイム処理とHTTP APIを混合で
使うべしだと・・・。ただ・・ビットコインの価格高いよね。
私には買えない。http_api.js//板情報 var F = require('./api-bitflyer.com.js'); F.Fapi.init = { key:"apikey", secret:"secretkey", method:"GET", path:"/v1/getticker", data:{product_code:"ETH_JPY"} }; F.Fapi.run();api-bitflyer.com.jsexports.Fapi = { init: { key: "", secret: "", method: "", path: "", data: "" }, run: function () { var request = require('request'); var crypto = require('crypto'); var timestamp = Date.now().toString(); var method = this.init.method; var path = this.init.path; var body = JSON.stringify( this.init.data ); var text = timestamp + method + path + body; var sign = crypto.createHmac('sha256', this.init.secret).update(text).digest('hex'); var pra = function(data){ let str = []; for (const key in data) { if (data.hasOwnProperty(key)) { str.push(key + "=" + data[key]); } } return "?" + str.join('&'); }; var options = { url: 'https://api.bitflyer.com' + path + (method.toUpperCase()==="POST"?"":pra(this.init.data)), method: method, body: body, headers: { 'ACCESS-KEY': this.init.key, 'ACCESS-TIMESTAMP': timestamp, 'ACCESS-SIGN': sign, 'Content-Type': 'application/json' } }; request(options, function (err, response, retload) { console.log(retload); }); } };
- 投稿日:2020-06-04T23:39:25+09:00
bitflyer.comでHTTP API使ってみたよ?
bitflyer.comでHTTP API使ってみたよ。?
使ってみて思ったことはリアルタイム処理とHTTP APIを混合で
使うべしだと・・・。ただ・・ビットコインの価格高いよね。
私には買えない。http_api.js//板情報 var F = require('./api-bitflyer.com.js'); F.Fapi.init.key = "APIKEY"; F.Fapi.init.secret = "secretkey"; F.Fapi.init.method = "GET"; F.Fapi.init.path = "/v1/getboard"; F.Fapi.init.data = { "product_code": "ETH_JPY" }; F.Fapi.run();api-bitflyer.com.jsexports.Fapi = { init: { key: "", secret: "", method: "", path: "", data: "" }, run: function () { var request = require('request'); var crypto = require('crypto'); var timestamp = Date.now().toString(); var method = this.init.method; var path = this.init.path; var body = JSON.stringify( this.init.data ); var text = timestamp + method + path + body; var sign = crypto.createHmac('sha256', this.init.secret).update(text).digest('hex'); var pra = function(data){ let str = []; for (const key in data) { if (data.hasOwnProperty(key)) { str.push(key + "=" + data[key]); } } return "?" + str.join('&'); }; var options = { url: 'https://api.bitflyer.com' + path + (method.toUpperCase()==="POST"?"":pra(this.init.data)), method: method, body: body, headers: { 'ACCESS-KEY': this.init.key, 'ACCESS-TIMESTAMP': timestamp, 'ACCESS-SIGN': sign, 'Content-Type': 'application/json' } }; request(options, function (err, response, retload) { console.log(retload); }); } };
- 投稿日:2020-06-04T16:30:21+09:00
[JS1日クッキング]APIサーバーをCircleCIで自動テスト
何かを簡単に作って、ちょっとした勉強になる。そんなシリーズになる予定のものの第3回です。
今回は、シンプルなAPIサーバーをCircleCIで自動テストをします。テストは前回にしてあるものを使います。
完成品はこちら -> sequelize-todo-api-server
材料
- ユニットテストをした前回のサーバー
- CircleCI
- jest-junit
作り方
1. テストメタデータの設定
テストの結果をテストメタデータとしてファイルへ保存できるようにします。CircleCIでテストした後、テストメタデータをCircleCIへアップロードすると、テスト結果がCircleCIのダッシュボードで確認できるようになります。
Jestのテストメタデータを作成するために、jest-junitをインストールします。
npm install -D jest-junitjest.config.js というファイルを作り、設定を書いていきます。
jest.config.jsmodule.exports = { reporters: ["default", ["jest-junit", { outputDirectory: "reports/jest" }]], };ここまでできたら、
npm run test
でテストを実行すると、reports/jestディレクトリ内にjunit.xmlが生成されるようになります。この中にテストメタデータが入っています。2. CircleCIの設定ファイルの用意
npm-scriptに
"test:ci": "export NODE_ENV=test && npx jest --ci --runInBand"を加えます。
--ci
と--runInBand
がCIでJestを使うときに必要になります。CircleCIで使用する設定ファイルを用意します。設定ファイルは、.circleciディレクトリ内のconfig.ymlに書きます。
.circleci/config.ymlversion: 2.1 jobs: build: docker: - image: circleci/node:lts - image: circleci/mysql:8-ram environment: MYSQL_USER: sequelize MYSQL_PASSWORD: sequepass MYSQL_DATABASE: database_test steps: - checkout - restore_cache: name: キャッシュの読み込み key: dependency-cache-{{ checksum "package-lock.json" }} - run: name: パッケージをインストール command: npm install - save_cache: name: キャッシュを保存 key: dependency-cache-{{ checksum "package-lock.json" }} paths: - node_modules - run: name: db を待機 command: dockerize -wait tcp://localhost:3306 -timeout 1m - run: name: JUnit をレポーターとしてテストを実行 command: npm run test:ci - store_test_results: name: テスト結果を保存 path: reportsjobsのbuild内に、使うコンテナと作業を記述していきます。
dockerキーに使用するコンテナを指定します。最初に使うイメージがコマンドを実行するコンテナになります。なので、Node.jsのコンテナを最初に書き、続いてDBのイメージを書きます。DBの設定は環境変数を使用して設定します。circleci/mysqlの環境変数は、MySQLの公式イメージと同じです。
ここでは、sequelizeで設定したユーザー名とパスワードだけでなく、使用するデータベースも設定します。使用するデータベースを設定しないとアクセスが拒否されます。
stepsキーに処理を順番に書いていきます。主に、
- checkoutでリポジトリからデータをダウンロード
npm install
でライブラリのインストールdockerize -wait tcp://localhost:3306 -timeout 1m
でDBが準備できるまで待つnpm run test:ci
でCI用のテストを実行- store_test_resultsでテストメタデータをCircleCIへアップロード
ということをしています。
3. CircleCIへリポジトリの登録
CircleCIで自動テストができるようにします。CircleCIに登録をした後、「Projects」のページに移動します。
「Set Up Project」をクリックします。
「Start Building」をクリックします。
新しいブランチ作って、そこにデフォルトの設定ファイルを加えるか尋ねられますが、今回は自分で用意したものを使うので、「Add Manually」をクリックします。
「Start Building」をクリックします。これで、CircleCIで使用するリポジトリの設定ができました。
4. 自動テストをする
では、実際に自動テストをしましょう。Githubにプッシュすると、自動的にCircleCIが処理を始めます。
「Piplines」で、CircleCIの処理中の様子や結果をみることができます。
処理が終わった後、「build」をクリックすると、以下のように処理結果をみることができます。
「TESTS」をクリックすると、テストメタデータからテスト結果を表示してくれます。
テストが失敗しているときは、以下のようにテストメッセージが表示されます。
5. ステータスバッヂの表示
CircleCIのステータスバッヂをGithubに表示することができます。CircleCIのステータスバッヂは、以下のようなものです。
これは、
[![CircleCI](https://circleci.com/gh/[Githubアカウント]/[リポジトリ]/tree/[ブランチ].svg?style=svg)]([画像のリンク先(大抵はGithubのブランチ)])の中の[]を全部埋めると、MDファイルにステータスバッヂを表示できます。例えば、今回使ったブランチだと、
[![CircleCI](https://circleci.com/gh/kei-lb6/sequelize-todo-api-server/tree/ci-test.svg?style=shield)](https://circleci.com/gh/kei-lb6/sequelize-todo-api-server/tree/ci-test)のようになります。これをREADME.mdに含めて、Githubでステータスバッヂを表示しています。
詳しくは下のページを参考にしてください。
Adding Status Badges - CircleCI
おわりに
CircleCIで自動テストをしました。workflowを使ってテスト成功後にデプロイをすることもできるので、使いこなせれば楽ができそうです。Netlifyもそうですけど、設定すればGithubにプッシュすれば自動に何かやってくれます系のサービスはとても便利ですね。
コード -> sequelize-todo-api-server
- 投稿日:2020-06-04T16:01:51+09:00
【array-foreach-async】forEach()でasync/awaitを使おうとして失敗した皆へ
AWS Lambda関数でNode.jsを使用し、forEach()でasync/awaitしたい状況に陥ったのですが、コードを書いて実行してもawaitの文が実行されていませんでした。色々調べたところ、Node.jsの
array-foreach-async
というライブラリを利用することで簡単に解決することができたので、まとめていきます。環境
- macOS
- AWS Cloud9
- Node.js 12
修正前の実行コード
今回の説明において不要なコードは省略しています。
const env = process.env const requestPromise = require('request-promise'); const AWS = require('aws-sdk'); const DB = new AWS.DynamoDB.DocumentClient(); exports.handler = async(event, context) => { // (省略) event.Records.forEach(async(record) => { // ここでasync // (省略) const data = await DB.put(dbParams).promise(); // 1つ目のawait console.log(data); // (省略) const req = await requestPromise.post(options); // 2つ目のawait console.log(req); }); return "success!" };実行すると、出力には
success!
のみが表示され、console.logは無視されます。forEach()がawaitの処理完了を待たずに終了し、Lambda関数が閉じてしまったためです。どちらか一方のawaitをコメントアウトしても結果は変わらず。forEach()ではasync/awaitが効いていないことが分かります。
そもそもArray.prototype.forEach()
自体がasync関数ではないため、引数のcallback関数にasync/awaitを付けたところで無意味ということです。修正後の実行コード
Node.jsの
array-foreach-async
というライブラリをインストールすることで、forEach()をasync関数にしたforEachAsync()
を使用できるようになります。
これを使えば、forEach()と同じ動作でasync/awaitを実現できます(参考:array-foreach-async - npm)。まずはライブラリをインストールします。
npm install array-foreach-asyncソースコードは次のようになります。
const env = process.env const requestPromise = require('request-promise'); const AWS = require('aws-sdk'); const DB = new AWS.DynamoDB.DocumentClient(); require('array-foreach-async'); // ライブラリの読み込み exports.handler = async(event, context) => { // (省略) await event.Records.forEachAsync(async(record) => { // 変更箇所 // (省略) const data = await DB.put(dbParams).promise(); console.log(data); // (省略) const req = await requestPromise.post(options); console.log(req); }); return "success!" };
forEach
をforEachAsync
に変更し、文の先頭にawaitを付けます。
実行すると、awaitの文が両方ともきちんと実行され、ログの出力を確認できました。補足
ずっとforEach()を使うことしか考えていなかったため後から気が付いたのですが、そもそもforEach()の代わりに
for〜of
を使用すれば解決できました。JavaScriptに慣れていなさすぎる...
修正前の実行コードを次のように変更すればOKです。const env = process.env const requestPromise = require('request-promise'); const AWS = require('aws-sdk'); const DB = new AWS.DynamoDB.DocumentClient(); exports.handler = async(event, context) => { // (省略) for(const record of event.Records) { // (省略) const data = await DB.put(dbParams).promise(); // 1つ目のawait console.log(data); // (省略) const req = await requestPromise.post(options); // 2つ目のawait console.log(req); } return "success!" };コードも簡潔であり、わざわざ
array-foreach-async
をインストールする必要がないので、どうしてもforEach()を使わなければならない状況以外では、素直にfor〜of
を使う方が良いかもしれませんね。ご参考までに。
- 投稿日:2020-06-04T16:01:51+09:00
forEach()でasync/awaitを使おうとして失敗した皆へ【array-foreach-async】
AWS Lambda関数でNode.jsを使用し、forEach()でasync/awaitしたい状況に陥ったのですが、コードを書いて実行してもawaitの文が実行されていませんでした。色々調べたところ、Node.jsの
array-foreach-async
というライブラリを利用することで簡単に解決することができたので、まとめていきます。環境
- macOS
- AWS Cloud9
- Node.js 12
修正前の実行コード
今回の説明において不要なコードは省略しています。
const env = process.env const requestPromise = require('request-promise'); const AWS = require('aws-sdk'); const DB = new AWS.DynamoDB.DocumentClient(); exports.handler = async(event, context) => { // (省略) event.Records.forEach(async(record) => { // ここでasync // (省略) const data = await DB.put(dbParams).promise(); // 1つ目のawait console.log(data); // (省略) const req = await requestPromise.post(options); // 2つ目のawait console.log(req); }); return "success!" };実行すると、出力には
success!
のみが表示され、console.logは無視されます。forEach()がawaitの処理完了を待たずに終了し、Lambda関数が閉じてしまっているためです。どちらか一方のawaitをコメントアウトしても結果は変わらず。forEach()ではasync/awaitが効いていないことが分かります。
そもそもArray.prototype.forEach()
自体がasync関数ではないため、引数のcallback関数にasync/awaitを付けたところで無意味ということです。修正後の実行コード
Node.jsの
array-foreach-async
というライブラリをインストールすることで、forEach()をasync関数にしたforEachAsync()
を使用できるようになります。
これを使えば、forEach()と同じ動作でasync/awaitを実現できます(参考:array-foreach-async - npm)。まずはライブラリをインストールします。
npm install array-foreach-asyncソースコードは次のようになります。
const env = process.env const requestPromise = require('request-promise'); const AWS = require('aws-sdk'); const DB = new AWS.DynamoDB.DocumentClient(); require('array-foreach-async'); // ライブラリの読み込み exports.handler = async(event, context) => { // (省略) await event.Records.forEachAsync(async(record) => { // 変更箇所 // (省略) const data = await DB.put(dbParams).promise(); console.log(data); // (省略) const req = await requestPromise.post(options); console.log(req); }); return "success!" };
forEach
をforEachAsync
に変更し、文の先頭にawaitを付けます。
実行すると、awaitの文が両方ともきちんと実行され、ログの出力を確認できました。補足
ずっとforEach()を使うことしか考えていなかったため後から気が付いたのですが、そもそもforEach()の代わりに
for〜of
を使用すれば解決できました。JavaScriptに慣れていなさすぎる...
修正前の実行コードを次のように変更すればOKです。const env = process.env const requestPromise = require('request-promise'); const AWS = require('aws-sdk'); const DB = new AWS.DynamoDB.DocumentClient(); exports.handler = async(event, context) => { // (省略) for(const record of event.Records) { // (省略) const data = await DB.put(dbParams).promise(); // 1つ目のawait console.log(data); // (省略) const req = await requestPromise.post(options); // 2つ目のawait console.log(req); }); return "success!" };コードも簡潔であり、わざわざ
array-foreach-async
をインストールする必要がないので、どうしてもforEach()を使わなければならない状況以外では、素直にfor〜of
を使う方が良いかもしれませんね。ご参考までに。
- 投稿日:2020-06-04T14:18:02+09:00
Node.jsをPHPで書き換えてみた
N予備校のプログラミング入門コース3章で作成した「秘密の匿名掲示板」をPHPで書き換えてみたので,その記録です。
きっかけ
スラスラわかるPHP(志田 仁美 著 翔泳社 刊)をやってみて,
「この間作った匿名掲示板,書き換えられるのでは?」
と思ったので。
スラスラわかるPHPをやってみた所感はこちら早速書き換える
仕様を変更したところ
- 認証の方式
おそらくN予備校ではBasic認証(alartみたいに上に出てくるやつ)を使っていたと思いますが, 書き換えの際にはスラスラわかるPHPのように,DBを使用する方式としました。
- TrackingID
N予備校で作成した際はCookieを利用してTrackingIDを実装していたと思いますが,セッションを利用する方式としました。その他細かい変更点はあると思うのですが,大きく変更したのはこちら2点です。
書き換えで苦労したところ
記事とユーザーの情報をどう関連付けるか
Laravelでは
userテーブル->id = articleテーブル->userid
としておけば情報を結びつけてくれていましたが,
今回はそれができない…ということで,とても苦労しました。
結局,セッションに該当するユーザー情報をもたせることで実現しました。
今回の場合,ユーザーのidとユーザー名が該当しました。TrackingIDをどう実現するか
Cookieを使うべきか?それともセッションを使うべきか?…という,なんとも根本的なところから悩みました。
こればかりは一人で解決できず,友人にも意見を求めたところ,セッションで実現でいいのでは?という意見をもらったので,結局セッションを使うということで,決着。
ざっくりとした実装方法は下記の通りです。ログイン時にランダムな文字列を予めセッションにセットしておく(仮にsecretidとします)
→書き込み時にpostテーブルに格納
→IDとして表示するのはsecretidの値所感
思ったよりも難しかった気がする
これはただ単に私の実力不足に起因するものだと思いますが,思ったよりも難しかった気がします。
勉強になった
セッションか?Cookieか?を考えたり,どうやってuserテーブルの情報をpostテーブルに入れるか…?を考えたり。
今まではmigrationに頼っていた部分がSQLになるので,SQLの勉強をしてみたり。
どうやって実現していたか?のロジックを一から考え直してみたり…
簡単に実現することはできませんでしたが,自分の実力不足を痛感するとともに,勉強になったことは多かったように思います。
- 投稿日:2020-06-04T13:38:54+09:00
nodebrew入れるときにnodeのPATHが遠らない話(マカー向け)
nodeのPATHが通らない
・.bashrcにはPATHをとおす記述を書く
・.bash_profileには毎回起動時にbashrcを読み込む記述を書く
上記二点は済なのに
.bashrcをコマンド叩いて毎回読み込ませないといけない地獄から抜け出せなかったので何かと思ったら
bashではなくzshを使っていたらしい。。http://pixelbeat.jp/bash_profile_not_working/ を参考に
~/.zprofile に ~/.bash_profile と同じ内容を追記したら直りました。ありがとうございました!
- 投稿日:2020-06-04T13:31:08+09:00
GoogleAPI for Node.js で Authorize までを共通化する
はじめに
Node.js を使用して GoogleAPI にアクセスする場合、SheetAPI であろうと DriveAPI であろうと認可の部分までは実は大体一緒です。
https://developers.google.com/docs/api/quickstart/nodejs
https://developers.google.com/sheets/api/quickstart/nodejs
https://developers.google.com/drive/api/v3/quickstart/nodejsあまりプロジェクト内で各サービスを行き来する事は無いのですが、どうせ共通なら一つのファイルにまとめて使いまわしたい、と思ってクラスを作りました。サンプルの内容をts化、クラス化して、
Promise
対応しています。
誰でも思いつく事だと思いますが、今後の自分のため + 同じような結論に行きついた方のためにまとめておきます。認可までを行うクラス
GoogleAuthorizer
という名称のクラスにしました。
適当な名前で、以下のファイルを保存します。ここではauthorize.ts
にしました。import fs from "fs"; import readline from "readline"; import { google } from "googleapis"; import { OAuth2Client } from "googleapis-common"; export class GoogleAuthorizer { private credentialsBuffer: string | null = null; private tokenBuffer: string | null = null; constructor( private scopes: string[], private tokenPath: string, private credentialsPath: string ) { } public async getOAuth2Client(): Promise<OAuth2Client> { if (this.credentialsBuffer) { return await this.authorize(JSON.parse(this.credentialsBuffer)); } else { return new Promise<OAuth2Client>((res, rej) => { fs.readFile(this.credentialsPath, async (err, content) => { if (err) { rej('Error loading client secret file:' + err); return; } // Authorize a client with credentials, then call the Google Drive API. this.credentialsBuffer = content.toString(); try { const o = await this.authorize(JSON.parse(content.toString())); res(o); } catch (e) { rej(e); } }); }); } } private async authorize(credentials: any): Promise<OAuth2Client> { return new Promise<OAuth2Client>((res, rej) => { const { client_secret, client_id, redirect_uris } = credentials.installed; const oAuth2Client = new google.auth.OAuth2( client_id, client_secret, redirect_uris[0]); if (this.tokenBuffer) { oAuth2Client.setCredentials(JSON.parse(this.tokenBuffer)); res(oAuth2Client); return; } // Check if we have previously stored a token. fs.readFile(this.tokenPath, async (err, token) => { if (err) { try { await this.getAccessToken(oAuth2Client); res(oAuth2Client); } catch (e) { rej(e) } return; } this.tokenBuffer = token.toString(); oAuth2Client.setCredentials(JSON.parse(token.toString())); res(oAuth2Client); }); }); } private getAccessToken(oAuth2Client: OAuth2Client): Promise<OAuth2Client> { return new Promise<OAuth2Client>((res, rej) => { const authUrl = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: this.scopes, }); console.log('Authorize this app by visiting this url:', authUrl); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); rl.question('Enter the code from that page here: ', (code) => { rl.close(); oAuth2Client.getToken(code, (err, token) => { if (err || !token) { rej('Error retrieving access token' + err); return; } oAuth2Client.setCredentials(token); // Store the token to disk for later program executions fs.writeFile(this.tokenPath, JSON.stringify(token), (err) => { if (err) { rej(err); return; } console.log('Token stored to', this.tokenPath); }); res(oAuth2Client); }); }); }); } }あまり気にしなくても良いかもしれませんが、ファイルIOがあまり発生するのもアレかなと思って、一度ファイルから読んだ情報はバッファに入れて再利用しています。
使用方法
先程保存した
authorize.ts
を読み込み、コンストラクタに以下の引数を指定して、まずはインスタンスを作成します。
その後、getOAuth2Client
をawait
付きで呼び出せば、必要なOAuth2Client
が取得できます。
引数 内容 1 使用するスコープ(配列) 2 トークンファイルのパス 2 認証ファイルのパス import { GoogleAuthorizer } from "./authorize"; class Main { constructor() { this.init(); } async init() { const SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']; const TOKEN_PATH = "token.json"; const CREDENTIALS_PATH = "credentials.json"; const a = new GoogleAuthorizer(SCOPES, TOKEN_PATH, CREDENTIALS_PATH); try { const auth = await a.getOAuth2Client(); console.log(auth); } catch(e) { console.error(e); } } } new Main();おまけ
冒頭で紹介した Google の Node.js サンプルページでは、とりあえず認証情報作るボタンがありますが、これをクリックすると QuickStart というプロジェクトが作成され、その中に適切な権限が与えられた認証情報が作成されて、認証ファイルがDLされます。
既存のプロジェクトに手動で追加する場合に困ったのですが、以下に方法が書いてありました。BigQueryのページですが、ここはサービス間で共通です。
- 投稿日:2020-06-04T13:06:19+09:00
�CircleCIに新しいDockerイメージ cimg が使えるようになったらしい!
cimgとは
CircleCIの次世代convenience imageとして新しいDockerイメージが登場しておりました。
より安定性とキャッシュ効率について考えられています。詳細はこちらのリンクを確認ください。
https://circleci.com/blog/announcing-our-next-generation-convenience-images-smaller-faster-more-deterministic/登場したわけ
「circleci/node」はnodeのDockerfile+CircleCIのライブラリ?で構成されています。
そのため、nodeに破壊的な変更が加わると「circleci/node」がうまく起動しないことが発生しました。
それを防ぐために登場したものがcimgのイメージです。
※間違っていましたらご指摘お願いします検証
どれくらいキャッシュ効率がいいのか試してみました。
各Nodeのイメージを使用するまでのpull時間を計測します。
(circleci側でキャッシュしているだろうという前提)
- build-node
- Dockerイメージ:Node
- build-circleci_node
- Dockerイメージ:circleci/node
- build-cimg_node
- Dockerイメージ:cimg/node
検証結果
数回実施しましたが平均的に以下のような結果になりました。
まとめ
「circleci/node」,「cimg/node」ともに早すぎてこれ以上差がつかないのかもしれない!?
登場したわけを聞いた時、今後の利用はcimg系の利用が必須ではないかなと思い、この記事を書きました。
こちらの情報(cimg)はCircleCIのユーザーコミュニティイベントで初めて聞きましたので、機会があればまた参加して色々聞いてみようかなー
皆さんもぜひこちらに参加してみてください。では、よいCI/CDライフを!!
検証に利用したソース
ちなみに、検証に使用したソースはこちらです。
config.ymlversion: 2 jobs: build-cimg_node: docker: - image: cimg/node:12.16 steps: - checkout - run: node --version build-circleci_node: docker: - image: circleci/node:12.16 steps: - checkout - run: node --version build-node: docker: - image: node:12.16 steps: - checkout - run: node --version workflows: version: 2 build_and_test: jobs: - build-cimg_node - build-circleci_node - build-node
- 投稿日:2020-06-04T08:18:51+09:00
Node.js の mysql2 で MariaDB のデータを削除 (Delete)
Async/Await を使います。
maria_delete.js#! /usr/bin/node // --------------------------------------------------------------- // maria_delete.js // // Jun/04/2020 // // --------------------------------------------------------------- var mysql = require('mysql2') // --------------------------------------------------------------- async function main(id_in) { const dotenv = require('dotenv') dotenv.config() const user = `${process.env.user}` const password = `${process.env.password}` const data_base = `${process.env.data_base}` var conn = await mysql.createConnection ({ host: 'localhost', user: user, password: password, database: data_base }) const command = "delete from cities where id = '" + id_in + "'" await conn.execute(command) conn.end() console.error ("*** 終了 ***") } // --------------------------------------------------------------- console.error ("*** 開始 ***") const id_in = process.argv[2] console.log (id_in) main(id_in) // ---------------------------------------------------------------実行コマンド
export NODE_PATH=/usr/lib/node_modules ./maria_delete.js t3327
- 投稿日:2020-06-04T08:10:34+09:00
Node.js の mysql2 で MariaDB のデータを更新 (Update)
Async/Await を使います。
maria_update.js#! /usr/bin/node // --------------------------------------------------------------- // maria_update.js // // Jun/04/2020 // // --------------------------------------------------------------- var mysql = require('mysql2') // --------------------------------------------------------------- function get_current_date_proc () { const today = new Date () var ddx = (1900 + today.getYear ()) + "-" + (today.getMonth () +1) ddx += "-" + today.getDate () return ddx } // --------------------------------------------------------------- function update_command_gen (id_in,population_in) { const today = get_current_date_proc() var command = "update cities set population = " + population_in command += " , date_mod = '" + today + "'" command += " where id = '" + id_in + "'" console.log (command) return command } // --------------------------------------------------------------- async function main(id_in,population_in) { const dotenv = require('dotenv') dotenv.config() const user = `${process.env.user}` const password = `${process.env.password}` const data_base = `${process.env.data_base}` var conn = await mysql.createConnection ({ host: 'localhost', user: user, password: password, database: data_base }) const command = update_command_gen (id_in,population_in) await conn.execute(command) conn.end() console.error ("*** 終了 ***") } // --------------------------------------------------------------- console.error ("*** 開始 ***") const id_in = process.argv[2] const population_in = process.argv[3] console.log (id_in + "\t" + population_in) main(id_in,population_in) // ---------------------------------------------------------------実行コマンド
export NODE_PATH=/usr/lib/node_modules ./maria_update.js t3326 721539800
- 投稿日:2020-06-04T08:00:17+09:00
Node.js の mysql2 で MariaDB のデータを読む (Read)
Async/Await を使います。
maria_read.js#! /usr/bin/node // --------------------------------------------------------------- // maria_read.js // // Jun/04/2020 // // --------------------------------------------------------------- function compare_by_key_proc (left,right) { var aa = left.key var bb = right.key var rvalue = 0 if (aa < bb) { rvalue = -1 } else if (aa > bb) { rvalue = 1 } return rvalue } // --------------------------------------------------------------- function sort_key_proc (dict_aa) { var array = new Array() for(var it in dict_aa) { array.push({'key':String (it), 'value':dict_aa[it]}) } array.sort (compare_by_key_proc) return array } // --------------------------------------------------------------- function dict_display_proc (dict_aa) { const array_aa = sort_key_proc (dict_aa) array_aa.forEach (function(unit_aa,index) { const key = unit_aa.key const value = unit_aa.value var out_str = key + "\t" out_str += value["name"] + "\t" out_str += value["population"] + "\t" out_str += value["date_mod"] console.log (out_str) }) } // --------------------------------------------------------------- async function read01 (mysql,user,password,data_base) { try { var conn = await mysql.createConnection({ host: 'localhost', user: user, password: password, database: data_base }) const sql_str = 'select * from cities' const [rows, fields] = await conn.execute(sql_str) return rows } catch (ee) { console.log(ee) return '' } finally { if (conn && conn.connection) { conn.end() } } } // --------------------------------------------------------------- async function main() { var mysql = require('mysql2/promise') const dotenv = require('dotenv') dotenv.config() const user = `${process.env.user}` const password = `${process.env.password}` const data_base = `${process.env.data_base}` const rows = await read01 (mysql,user,password,data_base) var dict_aa = new Object () rows.forEach(function(row) { dict_aa[row.id] = {"name": row.name, "population": row.population, "date_mod": row.date_mod} }) dict_display_proc (dict_aa) console.error ("*** 終了 ***") } // --------------------------------------------------------------- console.error ("*** 開始 ***") main() // ---------------------------------------------------------------実行コマンド
export NODE_PATH=/usr/lib/node_modules ./maria_read.js
- 投稿日:2020-06-04T07:58:02+09:00
Node.js の mysql2 で MariaDB のデータを作成 (Create)
Async/Await を使います。
maria_create.js#! /usr/bin/node // --------------------------------------------------------------- // maria_create.js // // Jun/04/2020 // // --------------------------------------------------------------- var mysql = require('mysql2/promise') // --------------------------------------------------------------- function dict_append_proc (dict_aa,id_in,name_in,population_in,date_mod_in) { var unit_aa = {} unit_aa['name'] = name_in unit_aa['population'] = population_in unit_aa['date_mod'] = date_mod_in dict_aa[id_in] = unit_aa return dict_aa } // --------------------------------------------------------------- function data_prepare_proc () { var dict_aa = new Object () dict_aa = dict_append_proc (dict_aa,'t3321','岡山',812763,'1950-10-23') dict_aa = dict_append_proc (dict_aa,'t3322','倉敷',783257,'1950-7-15') dict_aa = dict_append_proc (dict_aa,'t3323','津山',975241,'1950-1-2') dict_aa = dict_append_proc (dict_aa,'t3324','玉野',231864,'1950-6-22') dict_aa = dict_append_proc (dict_aa,'t3325','笠岡',769358,'1950-8-14') dict_aa = dict_append_proc (dict_aa,'t3326','井原',865792,'1950-9-12') dict_aa = dict_append_proc (dict_aa,'t3327','総社',438251,'1950-3-21') dict_aa = dict_append_proc (dict_aa,'t3328','高梁',352486,'1950-7-26') dict_aa = dict_append_proc (dict_aa,'t3329','新見',276951,'1950-10-2') return dict_aa } // --------------------------------------------------------------- async function main() { const dict_aa = data_prepare_proc () const dotenv = require('dotenv') dotenv.config() const user = `${process.env.user}` const password = `${process.env.password}` const data_base = `${process.env.data_base}` try { var conn = await mysql.createConnection ({ host: 'localhost', user: user, password: password, database: data_base }) const sql_str_drop = 'drop table if exists cities' await conn.execute(sql_str_drop) var sql_str_create = 'create table cities ' sql_str_create += '(id varchar(10), name varchar(20),' sql_str_create += ' population int, date_mod date)' await conn.execute(sql_str_create) for (var key in dict_aa) { console.log(key) var sql_str = "insert into cities " sql_str += "(id,name,population,date_mod) values (" const str_data = "'" + key + "','" + dict_aa[key].name + "'," + dict_aa[key].population + ",'" + dict_aa[key].date_mod + "')" sql_str += str_data await conn.execute(sql_str) } } catch (ee) { console.log(ee) return '' } finally { if (conn && conn.connection) { conn.end() } } console.log ("*** 終了 ***") } // --------------------------------------------------------------- console.log ("*** 開始 ***") main () // ---------------------------------------------------------------実行コマンド
export NODE_PATH=/usr/lib/node_modules ./maria_create.js