SWRに対する私見

  • まだ仲良くなれてない
  • API単位でキャッシュしてくれるみたい
  • POST主体のパラメータ引き渡しで、Axiosを経由して使ったが、パラメータの変更が反映されなかったりした…。
  • GET主体であれば柔軟にできそうではある

[React] SWRの使い方基礎 #React - Qiita

  • 現在のプロジェクトでは、パラメータのない、初回に一度だけアクセスして初期化を行うAPIアクセスに対しては使ってみようと思う。
  • 少しずつ仲良くなろうと思います。

AWS SDK Java v2 を使用して、大容量なファイルをMultipartでアップロードする。

  • 大容量のInputStreamやファイルをパート分けしてアップロードする。
  • バッファの容量(PART_BUFFER)や、パート単位の容量(PART_LIMIT)は同時使用ユーザ数等と考慮して設定しよう。
  • 参考サイト(ほぼまんま)

AWS SDK Java で S3 に少しずつ来たデータをバッファリングしつつ一つのファイルとしてアップロードするサンプルコード

  • 例外は各システムで適宜ハンドリングしましょう。

©okkez氏

 /**
     * Multipartアップロード
     * 
     * @param logger
         * @param executorService
     * @param bucketName
     * @param dest
     * @param is
     * @throws AppException
     */
    public static void multipartUpload(LambdaLogger logger, ExecutorService executorService, String bucketName, String dest, InputStream is)
            throws IOException, ExecutionException, InterruptedException {
        final S3Client s3 = getS3Client();
        final CreateMultipartUploadResponse response = s3
                .createMultipartUpload(builder -> builder.bucket(bucketName).key(dest));
        final String uploadId = response.uploadId();
        final ByteBuffer buffer = ByteBuffer.allocate(PART_BUFFER);

        try {
            final ReadableByteChannel channel = Channels.newChannel(is);
            List<Future<CompletedPart>> futures = new ArrayList<>();
            int partNumber = 0;
            while (channel.read(buffer) != -1) {
                if (buffer.position() > PART_LIMIT) {
                    logger.log("パートアップロード...パート番号:" + partNumber);
                    long contentLength = buffer.position();
                    buffer.flip();
                    partNumber++;
                    Future<CompletedPart> future = uploadMultipartUploadPart(executorService, s3, bucketName, dest,
                            uploadId, partNumber, contentLength, buffer.array());
                    futures.add(future);
                    buffer.clear();
                }
            }
            if (buffer.position() > 0) {
                logger.log("最終パートアップロード...パート番号:" + partNumber);
                long contentLength = buffer.position();
                buffer.flip();
                partNumber++;
                Future<CompletedPart> future = uploadMultipartUploadPart(executorService, s3, bucketName, dest,
                        uploadId, partNumber, contentLength, buffer.array());
                futures.add(future);
                buffer.clear();
            }

            // 全部のパートをアップロードするまで待つ
            while (!futures.stream().allMatch(Future::isDone)) {
                try {
                    TimeUnit.MILLISECONDS.sleep((100));
                } catch (InterruptedException ignore) {
                    // NOP
                    logger.log("スレッドが途中で終了:MultipartUploadの待機時");
                }
            }

            // CompletedPart を集める
            List<CompletedPart> parts = new ArrayList<>();
            for (Future<CompletedPart> future : futures) {
                try {
                    parts.add(future.get());
                } catch (ExecutionException | InterruptedException e) {
                    // NOP
                    logger.log("スレッドが途中で終了:CompletedPart集約時");
                }
            }

            // マルチパートアップロードの完了処理を行う
            final var completedMultipartUpload = CompletedMultipartUpload.builder().parts(parts).build();
            s3.completeMultipartUpload(
                    builder -> builder
                            .bucket(bucketName)
                            .key(dest)
                            .uploadId(uploadId)
                            .multipartUpload(completedMultipartUpload));
        } catch (IOException ioe) {
            ioe.printStackTrace();
            logger.log("大容量ファイルのアップロードに失敗");
            throw ioe;
        } finally {
            executorService.shutdown();
        }
    }

    /**
     * MultipartUploadを実行
     * 
     * @param executorService
     * @param s3
     * @param bucket
     * @param key
     * @param uploadId
     * @param partNumber
     * @param contentLength
     * @param bytes
     * @return
     */
    private static Future<CompletedPart> uploadMultipartUploadPart(
            ExecutorService executorService,
            S3Client s3,
            final String bucket,
            final String key,
            final String uploadId,
            final int partNumber,
            final long contentLength,
            final byte[] bytes) {
        return executorService.submit(
                () -> {
                    UploadPartRequest request = UploadPartRequest.builder()
                            .bucket(bucket)
                            .key(key)
                            .uploadId(uploadId)
                            .contentLength(contentLength)
                            .partNumber(partNumber)
                            .build();
                    UploadPartResponse response = s3.uploadPart(request, RequestBody.fromBytes(bytes));
                    CompletedPart part = CompletedPart.builder().partNumber(partNumber).eTag(response.eTag()).build();
                    return part;
                });
    }

InputStreamをByteBufferを使って読み込む

  • ファイルの分割を行う場合などに活躍する 正直、昔ながらのbyte配列書き出ししか見たことなかったので、
    後ほどByteBufferというか、NIO自体を学びなおそうと思っている。

  • ReadableByteChannelを使う

final ByteBuffer buffer = ByteBuffer.allocate(5 * 1024 * 1024);
final ReadableByteChannel channel = Channels.newChannel(is);
while (channel.read(buffer) != -1) {
  // 読みだしたbyteに対して、ByteBufferを経由して処理を行う。
}

ReadableByteChannelには、このようなJavaDocの記載がある

バイトを読み取ることができるチャネルです。  読込み可能なチャネル上で、並行して複数の読込み操作を実行することはできません。 チャネル上で読込み操作を開始したスレッドがある場合、新たな読込み操作を開始しようとする別のスレッドは、最初の操作が完了するまでブロックされます。 読込み操作とその他の入出力操作を同時並行で実行できるかどうかは、チャネルの種類によって決まります。

よくわからんけど、おそらく順々にしかファイル読み込みが行えないものかな?  ⇒要調査
NIOは並列処理を強化してあるので、InputStreamのようなIOに対応させるためのブリッジのようなものかもしれない。

【JavaScript】const、let、var

変数宣言をする際のconst、let、varをおさらいする。

const 変数名 = 値;
  • 再代入不可の変数宣言。
  • JSONやクラスなどのオブジェクトである場合、プロパティにアクセスして値を変更できるため、厳密にImmutableではない。
  • 最近は再代入をさせないコードが主流で、const以外使うなという風潮すらある。
let 変数名 = 値;
  • 再代入可能な変数宣言。
  • varと異なるのは、参照できるのが宣言後であること、同一の変数名はスコープ内で使用できないこと。
  • 再代入が必要である場合は、varを使わずletを使用する。理由は後述。
var 変数名 = 値;
  • 再代入可能な変数宣言。
  • 宣言前から参照をできてしまうため、スコープをめちゃくちゃ汚染する。
  • if や for のブロック内でも、ブロック外のスコープを汚染する。
  • 以下のような場合でも、参照できる。
function testFunc() {
    console.log(x); // undefined
    if (true) {
        var x = "abcde";
    }
    console.log(x); // abcde
}

まとめ

  • JavaScriptでは、varを使わないようにしよう

AWS SDK Java v2を使ってSESの一括送信を行う

SES(SimpleEmailService)のAPIを使って、メールの一括送信を行う。
利点

  • API呼び出しが回数を減らせる

注意点

  • 50件に1回の呼び出しが必要

  • Private VPCの場合、NATゲートウェイを使うことになる。(VPCエンドポイントがない)

やりかた

  • メールのテンプレートを作成する

E メールテンプレートの管理 - Amazon Simple Email Service

  • メール送信先毎に、BulkEmailEntryを作成する
// 宛先
Destination dest = Destination.builder()
        .toAddresses(/** 送信先 */)
        .build();
// テンプレート(置き換え内容)
ReplacementTemplate template = ReplacementTemplate.builder()
        .replacementTemplateData(/** JSONをStringにしたもの */)
        .build();
// コンテンツ
ReplacementEmailContent content = ReplacementEmailContent.builder()
        .replacementTemplate(template)
        .build();
// メール本体
BulkEmailEntry entry = BulkEmailEntry.builder()
        .destination(dest)
        .replacementEmailContent(content)
        .build();
  • 使用するテンプレートを指定
Template template = Template.builder()
        .templateName(/** テンプレートの名前 */)
        .templateData(/** BulkMailEntryのReplacementTemplateが設定されていなかった場合のReplacementTemplateData */)
        .build();
BulkEmailContent content = BulkEmailContent.builder()
        template(template)
        .build();
  • 50件毎に送信処理を行う
SendBulkEmailRequest bulkEmailRequest = SendBulkEmailRequest.builder()
        .bulkEmailEntries(/** BulkEmailEntryの実体 */)
        .defaultContent(/** BulkEmailContentの実体 */)
        .configurationSetName(/** SESに設定している送信設定の名前 */)
        .fromEmailAddress(/** fromアドレス */)
        .replyToAddresses(/** replyToアドレス */)
        .build();
SesV2Client sesv2Client = SesV2Client.builder()
        .region(Region.US_EAST_1)
        .build();
// 送信実行
SendBulkEmailResponse res = sesv2Client.sendBulkEmail(bulkEmailRequest);

Reactまわりの用語を知る その1

用語の意味だけをざっくりと

React

Meta(Facebook)のエンジニアが開発したJavaScriptライブラリ。
Webに用いられる要素(HTML、JavaScriptCSS)を書き出す処理をしてくれている。
Reactで作られたWebアプリケーションはメモリ上にアプリを持つことで、高速に画面のレンダリングを行える。

JSX

JavaScriptの中にタグを記入できる拡張言語。厳密にはReactの一部ではなく、Web技術の拡張。

Hooks

Reactバージョン16.8.0で導入された記法。
useから始まる関数を用いて

  • 状態管理
  • データ監視

etc...
を行えるようになった。
また、自作のHooksを作ることで、
UI部分とロジック部分を分離することが容易になった。

クラスコンポーネント

Hooksが導入されるまで主流であったReactのコンポーネント記法。
状態の管理などを、Reactのライフサイクルに応じたクラス内に記入する方法。
今でも、古い記事ではよく見る。

ReactNative

スマートフォンアプリケーションを作るためのReact。
Reactは、Nativeと区別するためにReactJSと呼ばれることもある。

たまには技術メモ:Docker

  • Dockerコンテナ同士の通信の場合は、ネットワークに所属させたうえで、コンテナ名 or ホスト名をパスとして使う。
  • docker network create -d ${ドライバ} ${ネットワーク名} でネットワークを作成できる。
  • ドライバは、none host bridge overlay の四種。
  • 基本bridge。複数デーモンあるDocker構成の場合はoverlayhostはDockerの仮想マシンと同じI/Fを持つ。noneは外部との通信がないもの。
  • docker inspect ${ネットワーク名}で同じネットワークを確認できる。

眠いのでここまで。実際運用に生きるかは分からん。
今週末にECS入門したい。