そごうソフトウェア研究所

SOA、開発プロセス、ITアーキテクチャなどについて書いています。Twitterやってます@rsogo

ExecutorServiceを利用して、並列処理を行うサンプル

今やっているアプリケーションの高速化を行うために並列処理を取り入れました。 やっている内容はレポートを作るのですが、APIで取得した100枚以上の画像をレポートに貼り付けるのですが、画像を取得する部分は並列化しています。

サンプルを作ったので、Githubにアップしています。 github.com

冬休みを利用して、解説を書きたいな。

Raspberry piのセットアップ備忘録

いろいろ実験用に使っていたラズパイにMinecraftのサーバーを入れてマルチを遊べるか試そうとしてます。

CUIでセットアップしていく。

キーボードの設定

キーボードはUSBで日本語レイアウトのものを接続した。 デフォルトは英字レイアウトで|などが入力できないので、変更する必要がある。

sudo raspi-configで、コンソールを立ち上げて、international settingでKeyboard settingで変更していく。キーボードは該当のものがなかったので、Microsoftの適当なキーボードを選択して、Japaniseカナレイアウトを選択した。

変更後、再起動で変更が反映された。

WiFiの設定

  1. アクセスポイントの確認。該当のアクセスポイントがスキャンできることを確認
sudo iwlist waln0 scan | grep ESSID
  1. アクセスポイントへの接続設定
sudo ifdown wlan0    // NWインターフェイスを停止しておく
sudo iwconfig wlan0 essid {SSID} key s:{パスフレーズ}
sudo ifup wlan0    // NWインターフェイスを起動

下記で、接続したアクセスポイントのSSIDが表示されればOK

sudo iwconfig wlan0
  1. インターフェイスを再起動して、ifconfigでIPアドレスが取得できていることを確認
sudo ifdown wlan0
sudo ifup wlan0
ifconfig

AWS SNSを使ったEメールの送信

最終的にはAWS SNSを使ってスマホにPush通知を送信する方法を確認したいですが、その前に簡単にEメールを送信すうる手順を確認したいと思います。

Topicの作成

f:id:begirama:20190416113146p:plain

以下の設定ができます。

  • 暗号化
  • アクセスポリシー
  • 配信再試行ポリシー
  • 配信ステータスのログ記録

サブスクリプションの作成

f:id:begirama:20190416113453p:plain

今回はテスト的にEメールを指定して、自分のメールアドレスをエンドポイントに指定してみます。

オプションとして、下記を設定できます。

f:id:begirama:20190416113751p:plain

サブスクリプションの確認

サブスクリプションの欄には保留中のエンドポイントとして先程のメールアドレスがリストされています。

f:id:begirama:20190416114500p:plain

下記のようなメールが対象に届いているのでConfirmします。

f:id:begirama:20190416114308p:plain

トピックへのメッセージの発行

f:id:begirama:20190416114048p:plain f:id:begirama:20190416114116p:plain

DynamoDBの勉強をしています

AWS Lambda + DynamoDBの組み合わせで サーバレスなアプリケーションを作ろうとしています。 DynamoDB をはじめとするNoSQLデータベースをちゃんと使ったことがなかったので今回改めて勉強しようと思います。

こちらのAWSで資料をお勧めしてもらいました。

各種設計に関してはマニュアルのベストプラクティスの章が参考になりそうです。 docs.aws.amazon.com

また、こちらのサイトではモデリングについて、パターン分けして詳しい説明を和訳されていて、参考になりました。

NoSQLデータモデリング技法 · GitHub

AWS Lambdaで必要な外部Jarも含めて一つのJarにする

AWS Lambdaでアプリを作っている時に必要となる外部のクラスが見つからずにjava.lang.NoClassDefFoundErrorが発生するケースがあります。

ビルド時は依存関係は解決できていてコンパイルエラーはでていんですが、これは外部のライブラリがパッケージングの際に含まれていないことが原因でした。

これはビルドツールにMavenを使っている場合はmaven-shade-pluginで解決できます。

マニュアルのIDE なしで Maven を使用した .jar デプロイパッケージの作成 (Java)にも記述があります。

プラグインセクションでは、Apache maven-shade-plugin は、Maven がビルドプロセス中にダウンロードして使用するプラグインです。このプラグインは、デプロイパッケージであるスタンドアロン .jar (.zip ファイル) を作成するために、jar のパッケージ化に使用されます。

stackoverflowでも同様の質問に対して、同じ解決策が出てました。

stackoverflow.com

homebrewでmysqlを8から5.7にバージョンを落としたときの対応

趣旨

Macにhomebrewで入れたMySQLを8から5.7にダウングレードした時の話をします。 事の発端は新しいMacBook Proに開発環境を移行しようとしたんですが、 homebrewでMySQLを入れるとバージョン8が入りました。

で、いろいろ変わっているようなので、今やりたいのはMySQL8対応じゃないし、問題を先送りすることにして、5.7にバージョンを落とすことにしました。 しかし、これはこれで小一時間はまりました。

発生した問題

homebrewは提供されていればバージョンを指定して過去のバージョンをインストールできます。brew uninstallして、brew installしましたが、起動が失敗します。

結論としては、アンインストールしても/usr/local/var/mysql/に各種ファイルが残っていて、それが原因で起動に失敗していました。/usr/local/var/mysql/以下のファイルをすべて削除することで解消しました。

やった内容

ここから先は、実際に試した内容です。

MySQL 8のuninstall

$ brew uninstall  mysql

MySQL 5.7のinstall

  • brew search {キーワード}で、どのパッケージが利用可能か確認
    ラッキーなことに5.5, 5.6, 5.7が使えそうです。
$ brew search mysql
==> Formulae
automysqlbackup              mysql++                      mysql-cluster                mysql-connector-c++          mysql-search-replace         mysql@5.5                    mysql@5.7 ✔
mysql                        mysql-client                 mysql-connector-c            mysql-sandbox                mysql-utilities              mysql@5.6                    mysqltuner

==> Casks
homebrew/cask/mysql-connector-python     homebrew/cask/mysql-shell                homebrew/cask/mysql-utilities            homebrew/cask/navicat-for-mysql          homebrew/cask/sqlpro-for-mysql
  • バージョンを指定してインストール
$ brew install  mysql@5.7
==> Downloading https://homebrew.bintray.com/bottles/mysql@5.7-5.7.23.high_sierra.bottle.tar.gz
Already downloaded: /Users/rsogo/Library/Caches/Homebrew/mysql@5.7-5.7.23.high_sierra.bottle.tar.gz
==> Pouring mysql@5.7-5.7.23.high_sierra.bottle.tar.gz
==> /usr/local/Cellar/mysql@5.7/5.7.23/bin/mysqld --initialize-insecure --user=rsogo --basedir=/usr/local/Cellar/mysql@5.7/5.7.23 --datadir=/usr/local/var/mysql --tmpdir=/tmp
==> Caveats
We've installed your MySQL database without a root password. To secure it run:
mysql_secure_installation

MySQL is configured to only allow connections from localhost by default

To connect run:
    mysql -uroot

This formula is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have this software first in your PATH run:
  echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.bash_profile

For compilers to find this software you may need to set:
    LDFLAGS:  -L/usr/local/opt/mysql@5.7/lib
    CPPFLAGS: -I/usr/local/opt/mysql@5.7/include
For pkg-config to find this software you may need to set:
    PKG_CONFIG_PATH: /usr/local/opt/mysql@5.7/lib/pkgconfig


To have launchd start mysql@5.7 now and restart at login:
  brew services start mysql@5.7
Or, if you don't want/need a background service you can just run:
  /usr/local/opt/mysql@5.7/bin/mysql.server start
==> Summary
🍺  /usr/local/Cellar/mysql@5.7/5.7.23: 317 files, 234.4MB

これでうまく行ってくれれば良かったのですが、起動させると、次のようなエラーがでました。

$ mysql.server start
Starting MySQL
. ERROR! The server quit without updating PID file (/usr/local/var/mysql/rsogo-Mac-Book-2.local.pid).

PID fileは存在しないし、困ってしまったのですが、/usr/local/var/mysql/にある.errファイル(私の環境ではrsogo-Mac-Book-2.local.errというファイル名でした)を見ると、既にibdata1があるというFatalレベルのエラーが発生していました。

今回は初期構築なので、MySQLを一度アンインストール後、/usr/local/var/mysql以下をバッサリ削除して、再度インストールすることで、下記のように正常に起動するようになりました。

$ mysql.server start
Starting MySQL
. SUCCESS! 

実際にはこんなにすんなり行かず、特に下記のようにサービスとして起動するようにすると、これ自体は成功して、実際アクセスすると接続でエラーになるので、設定がミスっているのではないかとか、いろいろ試行錯誤しました。勘でいろいろやるんじゃなく、エラーログを調べるのは大事ですね。

brew services start mysql@5.7

あと今回いろいろ調べるなかでhomebrewで入れると/usr/local/Cellar/mysql@5.7/5.7.23みたいなパスにインストールされるということも理解できました。

Mule ESBのフロー定義中にでGroovyスクリプトでカスタムのロジックを埋め込む

そういえば、Salesforce.comによるMulesoftの買収が発表されましたね。今後、どのようになっていくのか注目したいと思います。

www.mulesoft.com

さて、今回はMuleのフロー定義にGroovyのスクリプトを埋め込んでみたいと思います。 これができるとMuleで予め用意されたメッセージの変換ルール関数以外の独自処理をスクリプトで行うことができます。 Groovy以外にもJavaScriptなどのスクリプトを呼び出せます。

フロー定義

全体像

HTTPのGETリクエストを受け取り、URLのPATHのlxに置き換えるという処理をしています。 処理は<scripting:transformer>の中でやっています。名前空間http://www.mulesoft.org/schema/mule/scriptingを使うためにhttp://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd"を宣言に追加しています。

<mule
  xmlns="http://www.mulesoft.org/schema/mule/core"
  xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
  xmlns:http="http://www.mulesoft.org/schema/mule/http"
  xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd">

  <http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8086" basePath="groovy" doc:name="HTTP Listener Configuration"/>

  <!-- GET -->
  <flow name="GetFlow">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/*" doc:name="Recieve HTTP request" allowedMethods="GET">
      <http:response-builder reasonPhrase="#[flowVars['reason']]" statusCode="#[flowVars['statusCode']]"/>
    </http:listener>
    <logger doc:name="Log the payload" level="INFO" message="GET is called."/>

    <set-variable variableName="VarTableName"
                  value="#[message.inboundProperties['http.request.path']]"
                  doc:name="Variable"/>
                  
    <scripting:transformer name="stringReplaceWithParams">
      <scripting:script engine="groovy">
        <property key="oldStr" value="l" />
        <property key="newStr" value="x" />
        <scripting:text>
          return VarTableName.toString().replaceAll("$oldStr", "$newStr")
        </scripting:text>
      </scripting:script>
    </scripting:transformer>
  </flow>
</mule>

ステップバイステップで見ていきます。

HTTPリクエストのリッスン

8086ポートで、URLのベースのパスとして/groovyに来たリクエストを受け取る設定になっています。

<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8086" basePath="groovy" doc:name="HTTP Listener Configuration"/>

GETメソッドで呼び出されたときに、下記のフローが動作します。

  <flow name="GetFlow">
    <http:listener config-ref="HTTP_Listener_Configuration" path="/*" doc:name="Recieve HTTP request" allowedMethods="GET">

URLパスの取り出し

HTTPリクエストのパス(ホスト名、ポート名は含まず、それ以降)を取り出し、VarTableNameという変数に入れています。

    <set-variable variableName="VarTableName"
                  value="#[message.inboundProperties['http.request.path']]"
                  doc:name="Variable"/>

Groovyのスクリプトで文字列操作

    <scripting:transformer name="stringReplaceWithParams">
      <!-- scriptのエンジンとして、groovyを指定 -->
      <scripting:script engine="groovy">
        <!-- 変数に値を設定 -->
        <property key="oldStr" value="l" />
        <property key="newStr" value="x" />
        <!-- 実際のGroovyのコード。replaceAllでURLパスの文字列を変換して、応答として返す -->
        <scripting:text>
          return VarTableName.toString().replaceAll("$oldStr", "$newStr")
        </scripting:text>
      </scripting:script>
    </scripting:transformer>

テストしてみましょう

リクエス

次のURLに対して、GETメソッドのリクエストを出します

http://localhost:8086/groovy/helloworld

レスポンス

URLのパス(/groovy/helloworld)のうち、lxに置換した結果が返ってきています。

/groovy/hexxoworxd

curlコマンドで確認したら、こんな感じ。

$ curl http://localhost:8086/groovy/helloworld
/groovy/hexxoworxd

うまくいきましたね。