カテゴリー: tech

  • FlaskとThreadを使った並行処理と排他制御の実装

    FlaskとThreadを使った並行処理と排他制御の実装

    PythonのFlaskフレームワークは、小規模なアプリケーションから大規模なエンタープライズアプリケーションまで幅広い用途で使用されています。今回は、Flaskを用いたウェブアプリケーションで、複数のリクエストが同時に来た場合でも、裏側で動く処理を1つに制限する方法を解説します。

    この記事で取り扱う主要なテーマは以下の通りです:

    • Pythonのスレッドを使った並行処理
    • 排他制御によるリソースへの同時アクセス制限

    スレッドを使った並行処理

    Python の threadingモジュールを用いることで、スレッドを利用した並行処理を実装することができます。以下に具体的なコードを示します。

    import threading
    # スレッドを使う処理は関数にまとめます
    def process_request(request_data):
    # リクエストに対する処理を記述
    pass
    @app.route('/exec', methods=['POST'])
    def exec():
    # POSTリクエストのデータを取得
    request_data = request.get_json()
    # 新たなスレッドを作成して関数を実行
    thread = threading.Thread(target=process_request, args=(request_data,))
    thread.start()
    # レスポンスを即時に返す
    return jsonify({'status': 'processing'})

    このコードでは、POSTリクエストが/execエンドポイントに送信されると、新たなスレッドが作成され、process_request関数がそのスレッド上で実行されます。この関数はリクエストのデータを処理し、その間、メインスレッドは次のリクエストを受け付ける準備をします。

    排他制御による同時アクセス制限

    一方、裏側で動く処理を1つに保つためには排他制御が必要です。PythonのthreadingモジュールのLockを用いることで、排他制御を実現できます。以下に具体的なコードを示します。

    lock = threading.Lock()
    def process_request(request_data):
    with lock:
    # リクエストに対する処理を記述
    pass

    このコードでは、lockオブジェクトを用いてwithステートメントの中の処理が排他的に実行されるようになります。すなわち、一度に一つのスレッドだけがこの処理を実行でき、他のスレッドはロックが解放されるまで待機する必要があります。

    これらの方法を組み合わせることで、Flaskでの並行リクエストの受け付けと裏側での処理の排他制御を実現することができます。これにより、アプリケーションのパフォーマンスと安定性を向上させることが可能になります。

    この記事が皆様のPythonとFlaskのプロジェクトに役立つことを願っています。

  • PostgreSQLのテーブル定義を確認する方法:コマンドラインとGUIクライアントの違い

    PostgreSQLのテーブル定義を確認する方法:コマンドラインとGUIクライアントの違い

    PostgreSQLデータベースを操作する際、テーブルの定義を確認する必要がしばしばあります。

    テーブルの列名やデータ型を把握することで、適切なSQLクエリを作成し、データ操作を正確に行うことができます。

    一般的に、PostgreSQLのコマンドラインツールであるpsqlを使用してテーブルの定義を確認することが多いです。コマンドは、指定したテーブルの列名、データ型、修飾子、そして列の説明を表示します。

    例えば、テーブル名がhoge_tableの場合、次のコマンドを使用します:

    \d hoge_table

    しかしながら、全てのデータベース操作がコマンドラインから行われるわけではありません。

    GUIベースのデータベースクライアントツールを使用することが一般的であり、その中でもTablePlusはその使いやすさと直感的なインターフェースで高く評価されています。

    しかし、TablePlusやその他のいくつかのGUIクライアントツールでは、psql特有の\dコマンドが使用できません。

    その場合、次のSQLクエリを使用してテーブルの構造を確認することができます

    SELECT column_name, data_type
    FROM information_schema.columns
    WHERE table_name = 'hoge_table';

    このクエリは、テーブルのすべてのカラム名とそのデータ型を表示します。この方法は標準的なSQLクエリであるため、多くのデータベース管理ツールで使用できます。

    データベースを操作する際には、使用しているツールの特性を理解し、それに応じた最適な操作方法を選択することが重要です。それによって効率的かつ正確なデータ操作を行うことが可能となります。この記事がその一助となれば幸いです。

  • ターミナル操作の効率化:cdコマンドを使った直前のディレクトリへの素早い移動方法

    ターミナル操作の効率化:cdコマンドを使った直前のディレクトリへの素早い移動方法

    はじめに

    日々の開発作業でコマンドラインからファイルシステムを操作することは非常に一般的です。ディレクトリを行き来する際、完全なパスを何度も入力したり、タブ補完を使ってパスを探すのは時間の無駄ですよね。この記事では、ZshやBashなどのシェルで使える、直前のディレクトリに瞬時に戻る方法を紹介します。

    コマンドラインでのナビゲーションの効率化

    コマンドラインでの作業は速度と効率が重要です。頻繁にディレクトリを行き来する作業は、キーボード入力の手間だけでなく、思考の中断も引き起こします。そこで、直前のディレクトリに素早く戻る方法が必要です。

    cd - コマンド:直前のディレクトリに戻る

    このコマンドは、直前にいたディレクトリに素早く戻るためのコマンドです。これを使用すると、前回までにいたディレクトリに戻ることができます。以下にその使い方を示します。

    この一行のコマンドは、bashや他の多くのシェルでも同様に機能します。

    まとめ

    ターミナルでの作業をより効率的に進めるために、cd - のようなシンプルなコマンドが非常に役立ちます。頻繁にディレクトリを行き来する作業を行っている場合、このコマンドは手間を大幅に削減し、作業の効率を向上させることができます。

     

  • Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:80 -> 0.0.0.0:0: not allowed as current user. You can enable privileged port mapping from Docker -> Settings… -> Advanced -> Enable privileged port mapping

    Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:80 -> 0.0.0.0:0: not allowed as current user. You can enable privileged port mapping from Docker -> Settings… -> Advanced -> Enable privileged port mapping

     

     ports:
    - ${LOCAL_IP}:80:80
    - ${LOCAL_IP}:443:443

    docker-compose で上記のように 80, 443 のような 1023 番以下のport をマッピングさせようとしたところ、エラーになることがあります。

    Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:80 -> 0.0.0.0:0: not allowed as current user.
    You can enable privileged port mapping from Docker -> Settings... -> Advanced -> Enable privileged port mapping

    一般的にエラー文言に従い、Dockerの設定から “Enable privileged port mapping” を有効にしましたが、エラーが解消されない状況に陥りました。

    この問題に直面したとき、Dockerの設定でCLIツールのインストール方法を変更することで回避できました。

    具体的には、Dockerの設定の “Advanced” タブから “Choose how to configure the installation of Docker’s CLI tools” を開き、その設定を “User” から “System” に変更しました。

     

    この変更により、Dockerはシステムレベルで動作するようになり、これにより特権ポートを使用するための必要な権限を得ることができるようになるようです。

    結果として、ポート80と443が正常に割り当てられるようになり、エラーは解消しました。

     

     

  • Warning: Failed to run dot.    Download dot graphvizVersion 2.26 or versions greater than 2.31

    Warning: Failed to run dot. Download dot graphvizVersion 2.26 or versions greater than 2.31

    この警告メッセージは、dot コマンドが利用できないか、または適切なバージョンがインストールされていないことを示しています。dot コマンドは Graphviz パッケージの一部です。

    エラーメッセージ

    状況としては、何らかのアプリケーションまたはスクリプトを実行しているときに次のような警告メッセージが表示されることがあります。

    Warning: Failed to run dot.
    Download dot graphvizVersion 2.26 or versions greater than 2.31
    from www.graphviz.org and make sure that dot is either in your path
    or point to where you installed Graphviz with the -gv option.
    Generated pages will not contain a diagramtic view of table relationships.

    このメッセージは、dot コマンドが利用できないか、または適切なバージョンがインストールされていないことを示しています。

    解決方法

    この問題は、Debian ベースの Linux ディストリビューション(Ubuntu、Debian など)でapt-get を使用して解決することができます。

    1.  リポジトリを更新

    システムのパッケージリストを更新して、最新の情報を取得します。

    sudo apt-get update

    2. Graphviz のインストール

    次に、Graphviz パッケージをインストールします。

    sudo apt-get install graphviz

    4. インストールの確認

    インストールが成功したかどうかを確認するため、dot コマンドのバージョンを確認します。

    dot -V

    これで、バージョン情報が表示されれば、Graphviz は正常にインストールされ、dot コマンドが利用可能な状態になっています。

     

  • PythonでSnowflakeの不要なログを抑制する

    PythonでSnowflakeの不要なログを抑制する

    Snowflake Pythonコネクタは標準のPythonロギングモジュールを使用しています。

    このため、ロギングレベルを変更することで出力されるメッセージの制御が可能です。

    ただし、ロギングレベルを変更することは、接続の状態に関する重要な情報が隠される可能性があります。

    そのため、この変更を行う前に、その意味を完全に理解し、接続が安全であることを確認する必要があります。

    以下に、Snowflakeのロギングレベルを変更する方法を示します。

    1. まず、snowflake.connectorをインポートするPythonモジュールで、コネクタのメソッドを呼び出す前に以下のコードを追加します。これにより、警告またはそれ以上のレベルのログのみが出力されます。
    import logging
    logging.getLogger('snowflake.connector').setLevel(logging.WARNING)
    1. 上記のソリューションでも、すべてのSnowflakeメッセージが消えない場合は、以下のコードを使用して、すべてのSnowflakeロガーをより高いレベルに設定できます。
    import logging
    for name in logging.Logger.manager.loggerDict.keys():
    if 'snowflake' in name:
    logging.getLogger(name).setLevel(logging.WARNING)
    logging.getLogger(name).propagate = False

    この変更により、以下のようなエラーメッセージが表示されなくなります。

    eventType: 'RevocationCheckFailure',
    eventSubType: 'OCSPResponseFailedToConnectCacheServer|OCSPResponseFetchException|OCSPResponseFetchException|OCSPResponseFetchException|OCSPResponseFetchException',
    sfcPeerHost: 'xxxxx.ap-northeast-1.privatelink.snowflakecomputing.com',
    certId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    ocspRequestBase64: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    ocspResponderURL: 'http://o.ss2.us/',
    errorMessage: "254003: Could not fetch OCSP Response from server. Consider checking your whitelists : Exception - HTTPConnectionPool(host='ocsp.xxxxx.ap-northeast-1.privatelink.snowflakecomputing.com', port=80): Max retries exceeded with url: /retry/o.ss2.us/xxxxx+xxx= (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0xffff9c1ec190>: Failed to establish a new connection: [Errno -2] Name or service not known'))",
    insecureMode: False,
    failOpen: True,
    cacheEnabled: True,
    cacheHit: False

    このメッセージは、OCSP(Online Certificate Status Protocol)の検証が失敗した場合に出力されます。OCSPは、TLS接続の設定中に、接続先の証明書が有効であることを確認するためのプロトコルです。このメッセージが表示されるということは、SnowflakeコネクタがOCSP応答を取得できなかったことを示します。このような場合、接続が安全であることを確認した上で、ロギングレベルを変更することを検討してください。

    これらのステップを適用すると、Snowflake Pythonコネクタの不要なログ出力を抑制できます。ただし、これによりエラー情報が失われる可能性があるため、注意が必要です。常に接続が安全であることを確認し、必要に応じて適切なロギングレベルを選択してください。

  • AWS CloudWatch Logsからユーザーエージェントデータを分析し、OSとブラウザのシェアを視覚化する

    AWS CloudWatch Logsからユーザーエージェントデータを分析し、OSとブラウザのシェアを視覚化する

    イントロダクション:

    AWS CloudWatch Logsは、AWSリソース、アプリケーション、サービスのログデータを監視して保存するためのサービスです。

    この記事では、CloudWatch Logsからユーザーエージェントデータを収集し、PythonとGoogle スプレッドシートを使用してOSとブラウザのシェアを視覚化する方法を解説します。

    これはウェブサイトやアプリケーションのユーザー体験を最適化するために非常に有益です。

    手順1: CloudWatch Logsからログを取得する

    まず、CloudWatch Logsからユーザーエージェントデータを含むログを取得する必要があります。

    AWS Management Consoleにログインし、CloudWatch Logsのページに移動します。

    1. ロググループを選択し、ログストリームを開きます。

    2. クエリを使用してログデータをフィルターします。以下は、ユーザーエージェント情報を含むログエントリを抽出するサンプルクエリです。

    fields @timestamp, @message
    | parse @message /(?<ip>[\d\.]+) - - \[(?<timestamp>[^\]]+)\] "(?<http_method>[^"]+)" (?<status_code>[^ ]+) (?<size>[^ ]+) "(?<referrer>[^"]*)" "(?<user_agent>[^"]+)"/
    | stats count(*) by user_agent
    1. 上記のクエリをCloudWatch Logs Insightsのクエリエディタに貼り付け、実行します。

    2. 結果をCSVファイルとしてエクスポートします。

    手順2: Pythonを使用してログデータを解析する

    ログデータが得られたら、Pythonを使用して分析します。

    この記事では、user_agentsというPythonライブラリを使用します。

    このライブラリは、ユーザーエージェント文字列を解析して、デバイス、OS、ブラウザに関する情報を抽出するのに役立ちます。

    user_agents ライブラリをインストールします。

    pip install pyyaml ua-parser user-agents

    次に、以下のPythonスクリプトを使用して、ユーザーエージェント文字列からデバイス、OSバージョン、ブラウザ、ブラウザバージョンを抽出し、CSVファイルに出力します。

    import csv
    from user_agents import parse
    # ログファイルの読み込み
    with open('logs.csv', 'r') as file:
    logs = csv.DictReader(file)
    # 結果を保存するためのリスト
    results = []
    # 各ログエントリを処理
    for log in logs:
    user_agent = log['user_agent']
    count = log['count']
    # user_agents ライブラリでユーザーエージェント文字列を解析
    ua = parse(user_agent)
    device_type = 'Mobile' if ua.is_mobile else 'Tablet' if ua.is_tablet else 'PC'
    os = f"{ua.os.family} {ua.os.version_string}"
    browser = f"{ua.browser.family}"
    browser_version = f"{ua.browser.version_string}"
    # 結果をリストに追加
    results.append([device_type, os, browser, browser_version, count])
    # 結果を新しいCSVファイルに出力
    with open('parsed_logs.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(['Device', 'OS Version', 'Browser', 'Browser Version', 'Count'])
    writer.writerows(results)

    手順3: Google スプレッドシートでデータを視覚化する

    最後に、Google スプレッドシートでデータを視覚化します。

    1. Google スプレッドシートを開き、手順2で生成された parsed_logs.csv をインポートします。

    2. ピボットテーブルを作成します。これには、データ範囲を選択し、「データ」メニューから「ピボットテーブル」を作成します。

    3. ピボットテーブルエディターで、「行」に分析したいカテゴリ(例:Device, OS Version, Browser)を追加し、「値」に「Count」を追加して合計を計算します。

    4. ピボットテーブルのデータを選択し、「挿入」メニューから「グラフ」を選択して円グラフを作成します。これで、OSやブラウザのシェアを視覚化することができます。

    結論:

    CloudWatch Logsからのログデータ分析は、アプリケーションのパフォーマンスとユーザー体験を向上させるのに役立つ重要なステップです。

    このチュートリアルでは、Pythonのuser_agents ライブラリを使用してユーザーエージェントデータを解析し、Google スプレッドシートで視覚化する方法を紹介しました。

    この情報は、デバイスやブラウザの最適化、または特定のOSバージョン向けの機能開発に役立てれば幸いです。

  • Cognito 認証情報を活用した AWS Lambda の効果的なユーザー管理

    Cognito 認証情報を活用した AWS Lambda の効果的なユーザー管理

    導入

    現代のビジネス環境において、アプリケーションのセキュリティとユーザー管理は重要な柱です。AWS Lambda と Amazon Cognito を組み合わせることで、高度にスケーラブルでセキュアなサービスを効率よく構築できます。本記事では、Amazon Cognito で認証されたユーザーの情報を AWS Lambda で取得し、ビジネスプロセスに統合する方法に焦点を当てます。

    ビジネスの利点

    Amazon Cognito と AWS Lambda の組み合わせは、以下のビジネス上の利点を提供します。

    • セキュリティの強化: ユーザー認証情報を適切に処理することで、不正アクセスを防ぎます。
    • コスト効率: サーバーレスアーキテクチャを利用することで、リソースの利用に応じて課金され、余分なコストを削減します。
    • 拡張性: 需要に応じて自動的にスケールします。これにより、ビジネスが拡大してもパフォーマンスが維持されます。

    実装

    以下は、AWS Lambda 関数で Cognito の認証が通ったユーザーからメールアドレスを取得するステップバイステップのガイドです。

    ステップ1: IDトークンの取得

    まず、AWS Lambda 関数で HTTP リクエストのヘッダーから ID トークンを取得します。これは、Amazon Cognito によって発行された JWT(JSON Web Token)です。

    id_token = request.headers.get("x-amzn-oidc-data", "")

    ステップ2: トークンのデコード

    次に、JWT のペイロード部分をデコードします。JWT は3つの部分(ヘッダー、ペイロード、署名)で構成されており、ペイロードにはユーザー情報が含まれています。

    token_parts = id_token.split('.')
    payload_encoded = token_parts[1]
    padding_needed = 4 - len(payload_encoded) % 4
    payload_encoded += "=" * padding_needed
    payload_decoded = base64.b64decode(payload_encoded)
    payload_json = json.loads(payload_decoded.decode("utf-8"))

    ステップ3: メールアドレスの抽出

    最後に、デコードされたペイロードからメールアドレスを抽出します。

    email = payload_json['email']

    まとめ

    Amazon CognitoとAWS Lambdaを組み合わせることで、セキュアでスケーラブルなユーザー管理を実現し、ビジネスプロセスを効率化することができます。ユーザー認証情報の適切な処理は、アプリケーションのセキュリティを強化し、顧客の信頼を築く上で不可欠です。

    今回解説した方法を使用すると、簡潔にユーザーのメールアドレスを取得でき、これをビジネスロジックやユーザー通知など、さまざまな用途で活用することができます。

  • Microsoft Authentication Library (MSAL) との連携時に発生する接続エラーとその回避方法

    Microsoft Authentication Library (MSAL) との連携時に発生する接続エラーとその回避方法

    PythonでMSAL (Microsoft Authentication Library) を利用してAzure AD認証を実施する際に、接続エラーに直面することがあります。この記事では、その一般的なエラーと、これを解消するための回避策について詳しく解説します。

    エラーの例

    MSALを使用してAzure ADのトークンを取得する際に、以下のようなエラーメッセージが表示されることがあります。

    requests.exceptions.ConnectionError: HTTPSConnectionPool(host='login.microsoftonline.com', port=443): Max retries exceeded with url: /yourtenant.onmicrosoft.com/v2.0/.well-known/openid-configuration (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f84b146ad00>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))

    このエラーは、プログラムがMicrosoftの認証サーバーに接続しようとしたときに発生します。

    エラーの原因

    このエラーの原因は主に以下の通りです。

    1. network接続の問題: なんらかの問題で通信がうまくいかなかった

    2. DNSの問題: DNSが一時的に名前解決できない場合があります。これは一時的な問題である場合が多く、しばらく待ってから再試行すると解決することがあります。

    3. サーバーのオーバーロード: Microsoftのサーバーに対するリクエストが多すぎて、サーバーが反応しない場合があります。

    解決策

    上記のエラーに対処としてリトライを実装しました。

    コード例

    以下は、再試行ロジックを実装したPythonのコード例です。

    import time
    import requests
    import msal
    import logging
    logger = logging.getLogger(__name__)
    def acquire_token_with_retries(client_id, private_key, thumbprint, authority_url, max_retries=3, retry_delay=5):
    retries = 0
    while retries < max_retries:
    try:
    client_app = msal.ConfidentialClientApplication(
    client_id=client_id,
    client_credential={"private_key": private_key, "thumbprint": thumbprint},
    authority=authority_url
    )
    return client_app.acquire_token_on_behalf_of(user_assertion="YOUR_USER_ASSERTION", scopes=["https://graph.microsoft.com/.default"])
    except requests.exceptions.ConnectionError as e:
    logger.warning(f"Connection error occurred: {str(e)}. Retrying in {retry_delay} seconds...")
    retries += 1
    time.sleep(retry_delay)
    logger.error(f"Failed to acquire token after {max_retries} attempts.")
    return None

    このコードでは、トークン取得を試みる前に、最大リトライ回数を指定し、それを超えた場合はエラーを記録してNoneを返します。また、リトライの間に指定された秒数だけ遅延させます。

    まとめ

    MSALを使ってAzure AD認証を行う際に、接続エラーが発生する可能性があります。その際は、インターネット接続を確認し、再試行ロジックを実装することで、これらの一時的な問題を解決できる可能性があります。エラー発生時に適切なログ情報を収集することも重要です。

  • タイトル: S3バケットに関連付けられたLambda関数をAWS CLIで調査する

    タイトル: S3バケットに関連付けられたLambda関数をAWS CLIで調査する

    はじめに

    Amazon S3バケットにファイルがアップロードされたときにAWS Lambda関数を自動的にトリガーするのは、一般的な使用例です。しかし、プロジェクトが大規模になると、どのLambda関数が特定のS3バケットと関連付けられているのかを把握するのが難しくなることがあります。この記事では、AWS CLIを使用して、S3バケットに関連付けられたLambda関数を調査する方法について解説します。

    手順

    1. AWS CLIのインストールと設定

    AWS CLIがまだインストールされていない場合は、公式ドキュメントに従ってインストールしてください。次に、aws configureコマンドを使用してAWSアカウントの認証情報を設定します。

    2. S3バケットの通知設定を確認

    次に、以下のコマンドを使用してS3バケットの通知設定を取得します。このコマンドはバケットの名前を指定する必要があります。

    aws s3api get-bucket-notification-configuration --bucket YOUR_BUCKET_NAME

    このコマンドを実行すると、バケットに関連付けられた通知設定がJSON形式で表示されます。

    3. 結果の解析

    出力されたJSONの中で、LambdaFunctionConfigurations セクションに注目します。このセクションには、関連付けられたLambda関数のリストが含まれています。それぞれの項目では、Lambda関数のARN (Amazon Resource Name)、トリガーされるS3イベント、および任意のフィルタルールに関する情報が表示されます。

    実例

    以下は、実際の出力の例です(固有情報はマスクされています):

    {
    "LambdaFunctionConfigurations": [
    {
    "Id": "example-trigger-1",
    "LambdaFunctionArn": "arn:aws:lambda:region:account-id:function:example-function-1",
    "Events": [
    "s3:ObjectCreated:Put",
    "s3:ObjectCreated:Post"
    ],
    "Filter": {
    "Key": {
    "FilterRules": [
    {
    "Name": "Suffix",
    "Value": ".csv"
    }
    ]
    }
    }
    },
    {
    "Id": "example-trigger-2",
    "LambdaFunctionArn": "arn:aws:lambda:region:account-id:function:example-function-2",
    "Events": [
    "s3:ObjectCreated:Put",
    "s3:ObjectCreated:Post"
    ],
    "Filter": {
    "Key": {
    "FilterRules": [
    {
    "Name": "Suffix",
    "Value": ".txt"
    }
    ]
    }
    }
    }
    ]
    }

    この例では、2つのLambda関数がS3バケットに関連付けられています。

    それぞれが異なるファイルタイプ(.csvおよび.txt)のアップロード時にトリガーされます。

    まとめ

    AWS CLIを使用して、簡単にS3バケットに関連付けられているLambda関数の情報を取得することができます。これにより、システムの動作を理解し、必要に応じて設定を調整することが可能になります。