今さらの今さらですがコンテナを調べてみました

ドッカー、コンテナよく聞きますね。それこそ10年前から。

弊社でもDocker利用はありますが、活用が進んでいるとは言えません。

今さらながらコンテナとは何かを、自分で理解するために調べてみました。またコンテナといえば必ず上がってくるDocker、Kubernetes、そしてそれらの違いについても調べてみました。

コンテナとは

コンテナ(container)とは、アプリケーションの実行に必要な環境をパッケージする仮想化技術のことです。

コンテナというとみなさんも、船に積まれている鉄の箱や、大きなトラックで輸送している鉄の箱を目にしたことがあると思います。

仮想化技術のコンテナも船のコンテナと同様で、アプリケーションはミドルウェアなどをまとめ、軽量でスケール可能な形式でパッケージ化、ようは箱に入れるイメージです。このコンテナを利用することで実行環境に依存せず同じように動作させることができようになります。

仮想マシンとコンテナの違い

ページのみをこちらに置かせていただきまして、詳しくは下記ページを参照してください。

https://www.idcf.jp/words/container.html

メリット

1. 軽量で高速

これは実際にDockerを触ってみても感じます。

2. 移行・運用が楽

環境に依存しないため、本番環境とまったく同じ開発環境の構築が可能です。実際に楽です。

デメリット

1. コンテナに関する専門知識(学習コスト)が必要

運用はできたとしてもコンテナの作成からとなると学習にかける時間が必要になってきます。

2. ホストOSへの依存

ホストと同じOSファミリーである必要があります。
Windowsホスト上でLinuxコンテナを実行する場合など、異なるOSファミリーのコンテナを実行することはできません。

コンテナを扱うには

コンテナを扱うためには「Docker」「Kubernetes」などが代表的です。

Dockerとは

Docker は、アプリケーションをすばやく構築、テスト、デプロイできるソフトウェアプラットフォームです。Docker は、コンテナと呼ばれる標準化されたユニットにソフトウェアをパッケージ化します。コンテナには、ライブラリ、システムツール、コード、ランタイムなど、ソフトウェアの実行に必要なすべてのものが含まれています。Docker を使用すると、どのような環境にもアプリケーションをすばやくデプロイおよびスケールでき、コードを実行することができます。

https://aws.amazon.com/jp/docker/

Dockerといえばコンテナのイメージです。逆でもコンテナを扱うのであればDockerと認識される方も多いでしょう。

Dockerには上記にも上げましたがコンテナ型仮想化を使い、アプリケーションを開発・配置・実行するためのツールになります。

Kubernetesとは

Kubernetes (K8s)は、デプロイやスケーリングを自動化したり、コンテナ化されたアプリケーションを管理したりするための、オープンソースのシステムです。

https://kubernetes.io/ja/

読み方は「クバネティス」もしくは「クーベネティス」で「K8s」と表記されることもあります。もともとはGoogleが設計したもので、現在はCloud Native Computing Foundationがメンテナンスを行っています。

コンテナの運用管理をするためのツールで「コンテナオーケストレーションシステム」になります。

こちらもDockerより後に誕生していますが、利用されている方も多いと思われます。

DockerとKubernetesの違いは?

それぞれの説明にも書きましたが、Dockerはコンテナ型仮想化を使い、アプリケーションを開発・配置・実行するためのツールKubernetesはコンテナの運用管理をするツール、になります。

Dockerは1つのノード(サーバ)内で実行されるのに対し、Kubernetesはクラスター、いわゆる複数のノードにまたがったコンテナを管理できるものになります。

とは書いたものの、なかなかイメージしづらいかもしれませんが、Dockerで作成した複数のコンテナを1台の実況環境であるかのように管理できるものになります。

こちらにも記載がありました。

https://cloud-ace.jp/column/detail229/

したがいまして用途が別のものになります。どちらが良い悪いではなく、併用して使うことができます。

コンテナオーケストレーションシステムには何がある?

コンテナの運用管理をするためのツールが「コンテナオーケストレーションシステム」とありました。コンテナオーケストレーションシステムについても調べてみました。

https://xtech.nikkei.com/atcl/nxt/keyword/18/00002/080500086/

さらに調べると「ECS」「EKS」がでてきました。ECSは弊社でも利用しています。

ECSとEKSの違いはこちらにありました。

ECSとEKSの大きな違いは、ECSはAWSオリジナルのソフトウェアをベースに構築されている一方で、EKSはKubernetesをベースに構築されている、Kubernetesはオープンソースで世界中の開発者が開発を進めているという関係上、非常に機能が豊富で、アップデートも3か月に1回のペースで実施されています。

https://www.stylez.co.jp/aws_columns/cloud-native_development_on_aws_and_serverless/container_service_ecs_in_aws/

まとめ

コンテナといってもDockerのみを使っているというイメージがありました。コンテナ仮想化技術も改めて知ることができました。

またECSを利用しており、コンテナオーケストレーションサービスも使っているということが、今更ながら理解できました。

KubernetesやEKSといった他のコンテナオーケストレーションサービスも今後は使って、より良いコンテナ運用を目指したいと思います。

アンガーマネジメントで目指せストレスフリー!

みなさんは「アンガーマネジメント」という言葉を聞いたことはありますか?

「アンガーマネジメント」とは、
怒りのコントロールをすることで、怒りに伴うストレスを減らすことができる手法のことです。

社内研修などでアンガーマネジメントを扱う会社も増えており、近年注目されているメゾットです。

そこで今回は、下記の参考書籍を参考にアンガーマネジメントを習得することで、
できる限りストレスを感じない、ハッピーな毎日を目指すための考え方を学んでいきたいと思います!

1.まず怒りを感じたら

怒りを感じたらまずやることは、下記の通り7つだそうです。

「今」「この場」の怒りを収める7つの対症療法
1.「6秒ルール」で理性が働くのを待つ
2.「グラウンディング」で関係ないことを考える
3.自分の動作を実況して冷静になる
4.客観的に怒りを「10段階」で評価する
5.「タイムアウト」で立て直しの時間を作る
6.「自分との会話」で頭の中を切り替える
7.真っ白の紙を思い浮かべて「思考停止」する

「アンガーマネジメント超入門「怒り」が消える心のトレーニング」より

まずは、「考えない」「頭の中からその出来事をなくす」ことが重要なのだと思いました。
他のことに自分の関心を向けることで怒りを抑えるということですね。
7つの対症療法の中では、個人的には、『1.「6秒ルール」で理性が働くのを待つ』と
『7.真っ白の紙を思い浮かべて「思考停止」する』がすぐに実行しやすそうだなと感じました。
もし怒りを感じてしまったら、心の中で6秒数えて真っ白の紙をただ思い浮かべたいと思います。

あとは、『4.客観的に怒りを「10段階」で評価する』のように、怒りの程度を自分で評価し、
怒りのレベルが低ければ、自分の中で「そんなに怒ることでもなさそうだな」と
自分で冷静さを取り戻せるのではないかと思いました。

2.日頃から意識すること

怒らない自分を作る9つの習慣
1.ストレス解消の方法を変える
2.笑顔や穏やかな表情を心がける
3.関わる社会を選んで自分に良い制限を課す
4.語彙力を身につけて感情を正確に表現する
5.アンガーログを身に付けてイライラの傾向を知る
6.べきログで自分のコアビリーフを確認する
7.ハッピーログで幸せを自覚する
8.3コラムテクニックで怒りの境界線を広げる
9.「事実」と「思い込み」を切り分けて、余計な怒りをつけ加えない

「アンガーマネジメント超入門「怒り」が消える心のトレーニング」より

『2.笑顔や穏やかな表情を心がける』のように、私自身も笑顔でいると
自然と楽しい気持ちになってきたり、反対に悲しい顔や怒った顔をしてしまうと
自然とそういった気持ちになってきてしまうことがあります。
そのため、いつも口角を上げてにこやかで穏やかな表情を意識することで、
自然とハッピーな気持ちになれるのではないかと思いました。

また、「~べき」「~べきでない」という自分の凝り固まった考えとは違う考え方や
やり方に出会ったとき、「許せない→怒り」になってしまうこともあると思います。

自分とは異なる考え方ややり方に遭遇したとしても、自分の考えが、必ずしも誰にとっても
どの場面においても正解とは限らないという考え方を持ち、「そういう考え方もあるんだ」
「○○だからしょうがなかったのかな?」と柔軟な心でまず受け止めることが
大切なのかなと思いました。

さいごに

まず怒りを感じてしまったら、そのことを考えないようにすること、
そもそも、怒りを感じないように表情を意識することと柔軟な考え方を持つことで
ハッピーな毎日を目指していけたらいいなと思います。
学ぶだけでなく、意識的に実践→習得することが大切だと思うので、
日頃から意識していきたいと思います!

「絶対に怒ってはいけない」ということでなく、
怒らなくてもいいことは怒らない方が自分にとっても相手にとっても良いと思います。
もし、どうしても伝えたいことがあるとしたら、感情的に怒るのではなく
自分の意見と相手の意見のすり合わせをお互いに冷静で穏やかな気持ちで進めていけたら、
お互いの考えを受け止め合うことができ、解決したいこともうまく解決していけるのでは
ないかと思いました。

人の気持ちは伝染していくので、周りにハッピーな人がいれば、ハッピーになりますし、
反対に周りにイライラしている人やイライラ、怒りの感情をあらわにしている人がいると
そういった負の感情も伝染してしまいかねないので、アンガーマネジメントは
自分だけの問題ではないということを意識したいと思います。

なるべく負の感情を持たず、ハッピーに生きたいですね!

書籍の方には他にも「ムダに怒らない人になる心の持ち方」や
「上手な怒り方7つのルール」なども載っているので、もし良ければ見てみてください。

PokeAPIでポケモンGET!

自転車にまたがるとマッハ自転車のBGMが頭の中で流れ出します。岡村です。

今回は

  • PokeAPI
  • GoogleAppsScript
  • CloudFunctions
  • スプレッドシート

の4つを使ってポケモンGET機能を作ってみたいと思います。

やりたいこと

GoogleAppsScript上で関数を実行すると
スプレッドシートにポケモンのデータを含む新しい行が挿入されること。

それではやってみましょう!

PokeAPI

PokeAPIとはポケモンに関するデータを取得することができる
オープンソースのAPIです。

https://pokeapi.co/

今回取得したいデータは

  • 図鑑ナンバー
  • 名前
  • 画像URL
  • 解説

です。
アクセスするエンドポイントは

https://pokeapi.co/api/v2/pokemon-species/{id or name}/

です。
https://pokeapi.co/api/v2/pokemon/{id or name}/の方が
いろいろな種類のデータが取れるのですが、
日本語解説がpokemon-speciesの方にしかなかったので。

スプレッドシート

GETしたポケモンを格納するための
pokemonsシートを作っておきます。

列の定義は以下です。

  • A列:図鑑ナンバー
  • B列:名前
  • C列:画像URL
  • D列:解説

CloudFunctions

PokeAPIにポケモンデータ取得のリクエストを行います。
GoogleAppsScriptから行ったところ、
IPアドレスがブロックされたのか、
1回目以降データが取れなくなってしまいました。

People not complying with the fair use policy will have their IP address permanently banned.

公式ドキュメントFair Use Policyより引用

ですので前回同様PokeAPIへのリクエスト部分のみ、
CloudFunctionsを使って実装します。

ソースコードは以下のようにしました。

const fetch = require('node-fetch');
const functions = require('@google-cloud/functions-framework');

const END_POINT_POKEMON = 'https://pokeapi.co/api/v2/pokemon-species/';

/**
 * PokeAPIにポケモン取得をリクエストします。
 * 
 * 取得できた場合は、jsonオブジェクトを返します。ステータスは200です。
 * エラーが発生した場合は、空のjsonオブジェクトを返します。ステータスは500です。
 *
 * @param {Object} request クライアントからのリクエストに関する機能を提供するオブジェクト。
 * @param {Object} response クラアントへのレスポンスに関する機能を提供する提供するオブジェクト。
 */
functions.http('getPokemon', async (request, response) => {

  let returnJson = new Object();

  try {
    const url = END_POINT_POKEMON + request.body['id'];
    console.log('url:' + url);

    let responseObject = new Object(); 

    try {
      responseObject = await fetch(url); 
      returnJson = await responseObject.json();
      response.status(200);

    } catch(error) {
      throw new Error('PokeAPIへのリクエスト中にエラーが発生しました。error.message:' + error.message);
    }

  } catch(error) {
      console.error('エラーが発生しました。error:');
      console.error(error.stack);

      response.status(500);
  }

  console.log('returnJson:');
  console.log(returnJson);

  response.send(returnJson);

  return;
});

GoogleAppsScript

ソースコードは以下のようにしました。(DDD学習中🔥)

main関数からPokemonServiceクラスgetNewPokemon関数を呼び出します。



function main() {

  try {
    new PokemonService().getNewPokemon();
    
  } catch(error) {
    const errorMessage = 'エラーが発生しました。error:' + error.stack;
    console.error(errorMessage);
  }
}

getNewPokemon関数からPokeApiClientServiceクラスのrequestToPokeApi関数を呼び出します。

/** ポケモン機能のサービスクラスです。*/ 
class PokemonService {
  
  /** コンストラクタ。*/ 
  constructor() {
  
    /** 全国図鑑ナンバー最小値。*/ 
    this.minId = 1; 

    /** 全国図鑑ナンバー最大値。*/ 
    this.maxId = 1025; 
  }

  /** 
   * 新しいポケモンをGETし、スプレッドシートに追加します。 
   */ 
  getNewPokemon() {

    const id = Math.floor(Math.random() * (this.maxId + 1 - this.minId)) + this.minId;
    console.log('GETするポケモンの図鑑ナンバー:' + id);

    const response = new PokeApiClientService().requestToPokeApi(id);
    const pokemon = new Pokemon(response);
    new PokemonRepository().insertPokemon(pokemon);
  }
}
/** PokeApiのAPIクライアントサービスクラスです。*/ 
class PokeApiClientService {

  /** 
   * CloudFunctions経由でPokeApiへポケモン取得のリクエストを行います。 
   * @param id 取得するポケモンの図鑑ナンバー。
   * @return レスポンス。
   */ 
  requestToPokeApi(id) {

    // ご自身のCloudFunctionsのトリガーとなるURLを入力してください!
    const endPointGetPokemon = 'example.com';

    try {
      const headers = {
        "Authorization": `Bearer ${ScriptApp.getIdentityToken()}`
      }

      const params = {
        "id": id
      }

      const options = {
        "method": "POST",
        "headers": headers,
        "contentType": "application/json",
        "payload": JSON.stringify(params),
      }
    
      return UrlFetchApp.fetch(endPointGetPokemon, options);

    } catch (error) {
      throw error;
    }
  }
}

endPointGetPokemonにはご自身のCloudFunctionsのトリガーとなるURLを入力してください!
getNewPokemon関数にはCloudFunctionsがPokeApiを叩いたレスポンスが返ってきます。

レスポンスをPokemonクラスのコンストラクタに渡します。

/** ポケモンのEntityクラスです。*/ 
class Pokemon {

  /** 
   * コンストラクタ。
   * @param PokeApiからのレスポンス。
   */ 
  constructor(responseFromPokeApi) {

    const responseObject = JSON.parse(responseFromPokeApi.getContentText());

    const id = responseObject['id'];
    const name = responseObject.names.find(name => name.language.name === "ja-Hrkt").name;

    // 日本語解説がない場合は英語解説
    let text = '';
    try {
      text = responseObject.flavor_text_entries.find(entry => {
        return entry.language.name === "ja-Hrkt";
      }).flavor_text;

    } catch {
      // undefined
      text = responseObject.flavor_text_entries.find(entry => {
        return entry.language.name === "en";
      }).flavor_text;
    }

    /** 全国図鑑ナンバー。 */ 
    this.id = id;

    /** ポケモン名。 */ 
    this.name = name;

    /** 画像URL。 */ 
    this.imgUrl = 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/'+ this.id +'.png';

    /** 解説。 */ 
    this.text = text;
  }
}

図鑑ナンバー、名前、画像URL、解説をフィールドに持つエンティティとします。
スカーレット・バイオレットのポケモンたちは
まだ日本語解説が実装されてなかったので
日本語解説がなかった場合は英語解説をレスポンスから取り出します。

PokemonインスタンスをgetNewPokemon関数へ返し、
PokemonRepositoryクラスinsertPokemon関数へ渡します。

/** ポケモンのRepositoryクラスです。*/ 
class PokemonRepository {

  /** コンストラクタ。*/ 
  constructor() {

    this.scriptProperties = PropertiesService.getScriptProperties();
    const activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();

    // pokemonsシートを取得する
    this.pokemonsSheet = activeSpreadSheet.getSheetByName('pokemons');
  }

  /** 
   * ポケモンを挿入します。
   * @param pokemon ポケモン。
   */
  insertPokemon(pokemon) {
    const pokemonValues = Object.values(pokemon);
    this.pokemonsSheet.appendRow(pokemonValues);
  }
}

ポケモンデータをスプレッドシートの最終行へ挿入します。

では、ソースが書けましたら
実行!

実行結果

スプレッドシートにポケモンが追加されてますね!

あとがき

ポケモンはGETできましたでしょうか?
私はこの機能をdiscordのbotに組み込んで
みんなでポケモン図鑑を完成させるゲームにしました。
友人が今日の積み上げこと「きょうつみ」を投稿したら1ポイント。
5ポイントが溜まったらポケモンGET!
図鑑完成度を100%にしよう!★

ポケモンといえば最近?
推し声優がパモの声をやってるらしい!!
という不純な?理由で?
パモが好きかもしれない。かなり。

また何か作ったら共有します!

入社のご挨拶

はじめまして。中途入社の小松﨑と申します。

前職では学校法人や保険会社のバッグオフィスなど業務システムの改修を主に行っておりました。

かねてよりEC業界に興味を持っておりまして、グリニッジの提供するサービスであれば、
より多くのお客様に喜びを提供できると考え、この度入社する運びとなりました。

趣味はインドア中心で映画観賞、漫画鑑賞、たまに旅行に行きます。

映画は洋画を中心にさまざまなジャンルの作品を見ています。入社後、他のスタッフの方に勧められ
「シックスセンス」や「SE7EN」を見ました。
MCUをドラマを含めて網羅し続けていることが自慢です。

漫画は王道アクション系も好きですが、最近は「あかね囃」という落語の漫画を読んでいます。
いつか寄席にも行ってみたいです。

これまでに培ってきた経験を生かして、グリニッジのサービスをよりよいものにできるよう、
精進してまいります。
どうぞよろしくお願いいたします。

Thonnyのすすめ

こんにちは、窪田です。

プログラミングを始めてみようと思っている方にとって、障壁となるのはどのようなものでしょうか。

やってみたいけど難しそう、何から始めれば良いのかわからないなど、様々な要因があると思います。

なんとなくですが、心理的なハードルの高さとプログラムを書くまでの準備が難しいため、躊躇してしまっている人が多いような気がしています。

今回はプログラミングを始めてみようと思っている方に、おすすめの開発環境を紹介したいと思います。

紹介するのは Thonny というソフトです!

Thonnyとは何か

Thonnyとは、Pythonというプログラミング言語の初心者向けのIDE(開発環境)です。

Pythonは機械学習やデータ分析に強みを持つ汎用性の高いプログラミング言語で、コードの記述が短くシンプルなため初心者にも優しい言語だと思います。

ThonnyをPCにインストールするだけで、Pythonのプログラムを書くことと書いたコードを実行することができます。

公式サイト:https://thonny.org

Thonnyのインストール方法

Thonnyをインストールする方法について解説していきます。

公式サイト にアクセスし、画像赤枠のダウンロードリンクからPCのOSに合わせたインストーラーをダウンロードします。

ダウンロードしたインストーラーを起動すると、インストールモード選択画面が出てくるので「Install for me only (recommended)」をクリック

次の表示では「Next」をクリック

ライセンス同意画面に表示される文章を確認し、「I accept the agreement」にチェックを入れた後に「Next」をクリック

インストールするフォルダーを選択する画面で、インストールする場所を確認し、問題なければ「Next」をクリック

スタートメニューに表示される名前を確認し、問題なければ「Next」をクリック

デスクトップにショートカットアイコンを追加したい方は「Create desktop icon」にチェックを入れ、「Next」をクリック

今までの項目の確認画面が表示されるので、「Install」をクリック

以下の画像と同じように完了画面が表示されれば、Thonnyのインストールが完了です。

Thonnyの使い方

次はThonnyを起動し、実際にプログラムを書いてみましょう。

起動すると、以下の画像のような画面が表示されると思います。

画像赤枠の部分にPythonのコードを記述し、実行した結果が画像青枠の部分に表示されます。

今回はPythonを使って「Hello world!」と出力させたいので、print('Hello world!')と記述し、test.pyというファイル名で保存しました。

画像赤枠のボタンを押すと記述したPythonのコードが実行されます。

実行した結果として「Hello world!」が表示できました。

文字を出力するだけだと味気ないので、もう少し実用的な例として税込みの金額を求める処理を書いてみました。

金額として2024を入力すると、税込み金額の2226円が正しく出力できました。

まとめ

今回はプログラミング初心者でも簡単にPythonの開発ができるThonnyというソフトを紹介してみました。

Thonnyは簡単に使うことができるので、プログラミングを始めてみようと思っているけど躊躇している方はぜひ試してみてください。


ちなみにThonnyの発音がトニーなのか、ソニーなのか、わからないです。

個人的にはPython(パイソン)の開発環境なので、ソニーだと思っていますがどうなんでしょう。

慶應義塾大学大学院経営管理研究科(KBS)Executive MBA(EMBA)プログラム

今年からKBSのEMBAプログラムで学んでいるので活動を紹介します。
仕事をしながら大変な面もありますが、いくつになっても学校に行くというのは楽しいですね。

クラスのゴルフ部でラウンド

アントレプレナーシップ授業は活気があります。

LinkedInオフィスでLinkedIn活用について教えていただきました。

著名な海外教授によるグローバルな授業

スリランカでのビジネス可能性を現地で調査、1週間かけてスリランカ現地を周りました。

スリランカ現地メディアでも活動が取り上げられました。

学生所属企業一覧に当社グリニッジ株式会社も掲載されています。
https://www.kbs.keio.ac.jp/graduate/emba/dbook/2025/?pNo=1

EMBAプログラム詳細はこちら
https://www.kbs.keio.ac.jp/graduate/emba/index.html

Node.jsでサーバー動かしていたら時々止まる!?

Node.jsはイベントループで動作していて、それはシングルスレッドで動作する、async/awaitやpromise使って並列で動いているように見える・・・というのは、「node シングルスレッド」でググったらいろいろな先人達がブログを残してくれています。

そこで今回は、そういう動きをするということはわかるのだけど、実際そこを意識しないプログラムを作ってしまうと実運用システムにおいてどんな問題が起こるのか?について書きたいと思います。

今回は、24時間運用していて普通に動いていたNode.jsを使って作られたWebサーバー(ここではexpressサーバー)が突然応答なしになる、しかも時々・・・でもしばらく(数分~30分くらい)したら何事もなかったように正常に動作するようになる、みたいな事象が起きていた時のお話をします。

そもそも通常動作は?

基本的な通常動作は以下のようになります。(かなり簡略化しています)

左の図は1リクエストが1レスポンス返すまでに他のリクエストがない場合の図で、右の図は1リクエストが完了する前に2リクエストが要求されて、2リクエストが動けるまで(イベントループ回ってくるまで)waitしてから、スタートする図です。

基本的にはこれが3リクエストだろうがXリクエストだろうが、awaitなどでイベントループが回ってきたときに動作し、処理の途中で各リクエストがレスポンスを返すまで実行できるタイミングで実行します。

リクエストが1000リクエスト/分あったとしてもこれが動き、大体10ms~長くても500ms程度でイベントループで実行する処理が切り替わりながら動作するので、同時処理しているようにユーザーには見えるわけです。(そういえば、Windows95はマルチタスクでしたね)

問題動作って?

そして、今回問題になった時は以下の挙動をしました。

この30分レスポンスがなくなるリクエストがすべてのリクエストであれば、DBの単純負荷(スペック不足)などが考えられるのですが、レスポンスが30分かかるリクエストは特定のデータが格納されたデータだけでした。

さらに、DB接続はスレッドプールを利用して接続していたため、レスポンスが30分待ちのものがあってもスレッドプールに接続プールが残っていたらそちらを使うので他のリクエストは問題なく処理できていました。

ただ、この30分かかる処理がスレッドプールの上限(当時は10)を超えた場合・・・

すべてのDBリクエストがrequestの時点で「スレッドプール解放待ち」になります。(awaitから返ってこなくなります)

そうなると基本的にほぼすべてのリクエストはDBにデータを参照したり書き込んだりするわけで・・・

最終的には30分かかる処理が終わってスレッドプールが他のリクエストでも使えるようになると、突然サーバーは復帰し、何事もなかったかのように溜まった処理をすべて処理して、通常状態に戻ります。

結局は実装の問題

ちなみに今回の問題ではDBに1回のリクエストでAWSの制限クォータを超える大量のレコード数のWrite命令をしていて、それでもAWSががんばってくれた結果、30分で処理を終わらせてくれてた、というのが事の真相です。(AWSすごい!)

対処方法はシンプルで1回のリクエストでWriteするレコード数を減らして複数回のWrite命令でリクエストをするでした。

そのため「Node.jsのシングルスレッド関係なくてDBの使い方の問題じゃん!」と思うかもしれません。

しかし、今回はDBでロックしてしまっただけで、コードの書き方や他のリソースへのアクセスでイベントループに戻らないような長い処理(for文ループやBlock I/OのファイルRead/Writeなど)でも同じことが起こります。むしろDBのようにスレッドプールがなければ、即止まります。(というかそういう事象も起きました・・・)

回避方法はいくつか(WorkerThreadを使う、ロックするような処理は別サーバーや別プロセスで実行するなど)ありますが、それは結構大変だったりするので最終手段として、以下を気をつけてコードを書くようにするのがよいと思います。

  • 可能ならawait/asyncやpromiseにして細かくイベントループが動けるようにする
  • for文などのループ内処理が同期処理のみでループが抜けるのに時間がかかりすぎないかを確認して、かかりすぎるようであれば、await/asyncやpromiseで処理を分割する(必要であればログを仕込んで実行時間を確認する)
  • どこでイベントループに戻るかを意識する

マルチプロセスやマルチスレッドの場合には、同時処理(ディスパッチやクリティカルセクション、ミューテックスやセマフォなど)に関するリソース管理や実行順序などの注意が必要ですが、Node.jsでは他は動かないということに注意する必要があります。

システムが止まるというのは胃がキリキリする話ですが、そういったことが少しでも減って安定したシステムを提供できるようにしたいですね!

以上

ファビコンについて調べてみた

先日、弊社のコーポレートロゴ、サービスロゴが新しくなり、
ロゴの他にファビコンも差し替えました。

その際に、ファビコンについてブラウザのタブに表示されるぐらいの認識しかなかったので、
詳しく調べてみようと思いました。

ファビコン(favicon)とは?

ファビコンは「Favorite Icon」の略で、Webブラウザのタブやブックマークや検索結果に表示される小さな画像です。
Webサイトをブックマークする際や、複数のタブを開いているときに、ファビコンは瞬時にサイトを認識するための視覚的な目印になります

Webブラウザのタブ

ブックマーク

検索結果

ファビコンの重要性

ブランド認知の向上

ファビコンは、ウェブサイトのブランドを視覚的に強調するための強力なツールです。
シンプルで覚えやすいアイコンは、ユーザーがタブやブックマークからサイトを素早く認識できるようにします。

信頼性の向上

ファビコンが設定されていないサイトは、未完成や信頼性の低いサイトと感じられてしまうことがあります。
特に商業サイトやブログでは、ファビコンがあることでプロフェッショナルな印象を与えることができます。

ファビコンの作り方

ファビコンはツールを使って簡単に作成できます。
以下は主な作成ツールです。

  • オンラインジェネレーター
    Favicon.ioReal Favicon Generatorといったツールを使うと、画像をアップロードするだけでファビコンを生成できます。
  • デザインソフト
    Adobe PhotoshopやIllustratorなどのグラフィックデザインソフトを使って、自作のアイコンを作ることも可能です。
    ファイルを作成したら、ICOフォーマットに変換します。

ファビコンの最適なサイズとフォーマット

ファビコンのサイズやフォーマットは、ウェブブラウザやデバイスによって異なるため、
適切なサイズで複数のフォーマットを用意することが大事です。

サイズ用途フォーマット
16x16ブラウザのタブやアドレスバーICO
32x32デスクトップのショートカットPNG
180x180AppleのホームスクリーンアイコンPNG

.ico形式だけでも多くのブラウザで対応可能ですが、
より高品質で柔軟な対応を求める場合は、.ico形式とPNGSVGなどの形式を併用して、
各デバイスやブラウザに最適化するのがベストです。

ファビコンがSEOに与える影響

ファビコン自体が直接的に検索エンジンに影響を与えることはありませんが、
ユーザーエクスペリエンスに関しては間接的にSEOに貢献する可能性があります。

クリック率の向上

ファビコンが適切に設定されていると、ユーザーがサイトをより覚えやすくなり、
再訪問やブックマークからのクリック率が上がることがあります。

信頼性の向上

特にスマートフォンのホーム画面に追加された場合、
ファビコンがしっかり表示されていることで信頼性が高まります。

まとめ

ファビコンは、小さくても大きな影響力を持つウェブサイトの重要な要素になります。
ブランドを視覚的に認識させ、プロフェッショナルな印象を与え、
ユーザーのエクスペリエンスを向上させることができます。

設定方法も簡単なので、まだ導入していない方はぜひ導入してみてください。

入社のご挨拶

はじめまして。
この度、開発職として中途で入社しました佐藤と申します。

前職では受託開発というかたちで、経費精算やヘルスケア領域などのWEBアプリケーション開発に従事していました。

主に以下のような点に惹かれ、かつご縁がありこの度はグリニッジに入社することと相成りました。

  • 事業会社ということもあり、エンジニアもユーザーファーストの意識を持っていること。
  • フルスタックエンジニアとしての経験ができそうであること。
  • 職場の雰囲気が良いこと。(一番の決め手です)

私は「何をやるか」より「誰とやるか」に重きを置いています。
好きな人とであれば、なんでもできるような気がします。なんでも挑戦できるような気がします。
勇気、モチベーション、パフォーマンス、忍耐力―――心の奥底からパワーが沸き上がる感覚ですね。
もちろん、私だけでなく、私が皆さんにもパワーをお裾分けできるような存在になりたいと思います。
グリニッジの皆さん、どうぞよろしくお願いいたします!

また、エンジニアという枠に囚われずに、ビジネスサイドも意識したエンジニアリングに力を入れていきたいです。
グリニッジの企業価値向上へ向けて、目の前のキーボードを叩いていきたいと思います。

習慣化したい!タスクマネジメント

仕事もプライベートも
やりたいことがたくさん。
けど時間が足りない…!

そんな時、時間を有効に使うには
スケジュール管理が不可欠!
ということで、タスク管理をしようとしたものの
こんな失敗をしたことは、ありませんか?

タスクの規模が大きい
タスクがざっくり曖昧すぎてしまうと…

工数や作業時間が読めない
何から着手したらいいかわからない
結果、思っていたより時間がかかってしまい
タスクを予定通りに完了できない。


一度はこんな失敗したこと
あるんじゃないでしょうか。

こういった結果にならないためにも
タスクブレイクダウンをおすすめします!

タスクブレイクダウン(TB)とは?
タスクを細分化して
効率を上げる手法です。


具体的には、以下の3ステップを行います。

STEP 1  完了までの流れを決める
STEP 2  流れで必要な作業を洗い出す
STEP 3 作業に必要な時間を見積もる

このステップを考える時は、7W1Hを使います。

いつまでに(When)
どこで(Where)
誰が(Who)
誰に(Whom)
何を(What)
なぜ(Why)

どれから(which)
どのように(How)

細分化することで、完了までの流れと
必要な時間が明確になり
より現実的な時間管理が行えます

あとは細分化されたタスクに、集中するだけです!

この手法のよい点は、大きいタスク完了までには
時間がかかりますが、細分化されたタスクであれば
タスク完了数も増え、短いスパンで達成感が得られ
モチベーション維持がしやすいところです。

今回は、タスクブレイクダウンについて
紹介させていただきましたが、タスク管理方法について
グリニッジのスタッフblogの投稿でも紹介されていたり
チームやプロジェクトでも、日々タスク管理が行われています。

タスク管理方法は、他にもいろいろあるので
他の手法も取り入れ、個人のタスク管理能力を高めることで
時間を有効に使っていきたいです!