Open8

Deno 色々

nukopynukopy

標準ライブラリ

https://zenn.dev/uki00a/books/effective-deno/viewer/deno-std

依存の管理

deps.ts or import maps

https://zenn.dev/uki00a/books/effective-deno/viewer/manage-deps-in-a-centralized-way

テスト

https://zenn.dev/uki00a/books/effective-deno/viewer/write-tests

CI

古いから注意。標準ライブラリとかよく使われてるモジュールの GitHub Actions の YAML を参考にすれば OK。そんなにむずくない。

https://zenn.dev/uki00a/books/effective-deno/viewer/setup-ci

パーミッション

https://zenn.dev/uki00a/books/effective-deno/viewer/give-deno-only-the-minimum-privileges

  • -A--allow-all は本番環境で使わないように
deno run -A main.ts
  • 必要な権限のみオプションで指定する。何の権限が必要になっているかを明示的にする。
deno run --allow-read --allow-write --allow-env main.ts
nukopynukopy

Deno におけるテスト

nukopynukopy

テストの並列実行について

ChatGPT

エラーメッセージ

error: Started test step while another test step with sanitizers was running:

このエラーメッセージは、Denoのテストランナーが同時に複数のテストステップを実行しようとした際に発生しています。Denoのテストフレームワークでは、テスト間でのリソースのクリーンアップ("sanitizers"と呼ばれる)を保証するために、一度に一つのテストステップのみが実行されるように設計されています。このエラーは、特にDeno.test{ sanitizeResources: false, sanitizeOps: false }のようなオプションを使用せずに、非同期操作やリソースの開放を伴うテストが適切にハンドリングされていない場合に起こりがちです。

エラーメッセージが示しているのは、tail の基本的な動作: 指定された行数をファイルから正確に取得するというテストが複数同時に実行されており、それらのテストが互いに干渉している状態をDenoが検出したということです。これは、テストが非同期操作を行っていて、それらの操作が完了する前に次のテストが開始された場合に起こります。

解決策

  1. 非同期テストの正しい管理: 非同期操作を含むテストでは、操作が完了するのを待つためにawaitを適切に使用してください。また、リソース(ファイルハンドル、ネットワークコネクションなど)を開放する処理をfinallyブロック内で行い、テストが終了する前に必ずクリーンアップするようにしてください。

  2. テストの隔離: 同時に実行されるテスト間で干渉が発生しないように、テストを適切に隔離します。テストが互いに独立していることを確認し、共有される状態やリソースがないようにしてください。

  3. テストオプションの利用: Deno.testにはsanitizeResourcessanitizeOpsなどのオプションがあり、これらをfalseに設定することでリソースやオペレーションの自動クリーンアップを無効にすることができます。ただし、これらのオプションを使用する場合は、手動でリソースのクリーンアップを確実に行う責任が生じます。

Deno.test({
  name: "あなたのテスト名",
  fn: async () => {
    // あなたのテストロジック
  },
  sanitizeResources: false,
  sanitizeOps: false
});

このエラーメッセージが出る原因と解決策を理解し、テストの設計を見直すことで、テストの正確性と信頼性を高めることができます。

nukopynukopy
nukopynukopy

JSON 形式のロギング

import * as log from "https://deno.land/std@0.224.0/log/mod.ts";

log.setup({
  handlers: {
    default: new log.ConsoleHandler("DEBUG", {
      formatter: log.formatters.jsonFormatter,
      useColors: false,
    }),
  },
});

log.formatters.jsonFormatter の中身を見ると意外と大したことしてない。細かなコンテキスト、例えば Go の zap の caller フィールドみたいなのはどうやって取得するんだろう。

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.
import type { LogRecord } from "./logger.ts";

export function jsonFormatter(logRecord: LogRecord): string {
  return JSON.stringify({
    level: logRecord.levelName,
    datetime: logRecord.datetime.getTime(),
    message: logRecord.msg,
    args: flattenArgs(logRecord.args),
  });
}

function flattenArgs(args: unknown[]): unknown {
  if (args.length === 1) {
    return args[0];
  } else if (args.length > 1) {
    return args;
  }
}

export const formatters: {
  jsonFormatter(logRecord: LogRecord): string;
} = {
  jsonFormatter,
};