【LINE】「この写真は破損しているため表示できません」と表示され、投稿できない

現象

LINEグループのアルバムに写真を投稿しようとして、写真を選択すると「この写真は破損しているため表示できません」と表示され、投稿できなかった。 続きを読む 【LINE】「この写真は破損しているため表示できません」と表示され、投稿できない

【教訓集】

(随時追記中・・・)

コーディング(共通)

  • 変数名、メソッド名は分かりやすく
  • エラーチェックはメソッドの先頭で行い、エラーがあればその場で適切なメッセージを出し、returnする
  • プログラム自体の戻り値は正常終了した場合は0、それ以外の場合は1以上を返す
  • 長い処理時間が見込まれる場合は、カーソルを砂時計に
    また、await/asyncを利用して応答なし状態にならないようにする。

コーディング(C#、VB.NET)

  • 文字列結合はStringBuilderを使う
  • DataTableを編集する場合は、BeginLoadData、EndLoadDataを使う
  • DataRowを編集する場合は、BeginEdit、EndEditを使う
  • VB.NETで開発するときには、「Option Strict On」「Option Explicit On」を行う
  • VB.NETで開発するときには、namespaceを記述する(名前がかぶってしまうのを防ぐ)
  • VB.NETで開発するときには、Moduleは利用しない。Classを利用する
    (Module内でPublicで宣言してしまうと、どこからも参照可能になりカオスになる)
  • MessageBoxなど、多くの場所で利用する処理は直接呼び出さず、ラッパーを作って利用する。こうすることにより、仕様が変わった際に1か所だけ修正すれば済む、また、ほぼ似てるけど少し違う実装が存在する、などの問題を防げる。

テスト

  • 複数同時アクセス、大量アクセスを試す
  • タブキー押下でのタブ順移動

動作が遅い

  • ログファイル出力が過剰でないか
  • ウィルス対策ソフトの監視対象になっていないか
  • ネットワーク、プロキシーは適切か
  • メモリが不足していないか
  • 他のソフトが動作していないか
  • (DB)物理ファイルの拡張が起こっていないか

リリース

  • 不具合改修版をリリースするときには、プログラム入れ替えの他、不具合に起因してDBに保存されたままになっている異常データの修復も忘れない。

タスクスケジューラ

  • ログオンユーザーの違いにより、動作が変わる可能性あり
  • 直接プログラムを呼び出さず、batファイルからプログラム呼び出しを行う。その際にカレントディレクトリを指定する

バッチ

  • 目的、引数の説明などを簡潔にバッチファイルの先頭に記述する

設定変更

  • 本番機でいきなり設定変更しない。本番機に影響の出ない検証機にて、設定変更し、動作確認を行う。また、その設定変更を行う際には手順書を作成して、本番機の設定変更の際に利用する。
  • 設定を変更する際。設定画面の場合は画面キャプチャを、設定ファイルの場合はファイルを取っておく。こうすることで、どこを変えたかが追える。また、バージョンアップした際に、どの部分を変更すればよいかがわかりやすくなる。(設定ファイルの場合はWinMergeなどでDiffを取れるような状態にしておくことが望ましい)

PostgreSQL

  • 1日1回、VACUUM ANALYZEする
  • 月1回、REINDEX、CLUSTERする

運用監視

  • 停電などで機器が本来の手順でシャットダウンされなかった場合、電源を入れなおしても復旧しない場合がある。(UPSの利用)
  • サービスが落ちていないかの監視が必要かを検討する(死活監視)
  • 障害が発生したと同時にメールサーバも落ちてしまい、落ちたことすら分からなくなってしまう、などの事態が発生しないかを考慮する
  • DB、ログサイズの日々の増加量を確認する

役立つ法則

【C#】async/awaitを利用したマルチスレッド実装テンプレート

ボタン押下時の処理にて、以下のような要件を想定したサンプルです。
(.NET Framework4.5.1利用)

開始

A処理
↓   ↓
B処理  C処理 ※
↓   ↓
D処理

終了

※ここだけ並行処理可能なので、マルチスレッド化したい。

using System;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AsyncSample
{
    /// <summary>
    /// async/awaitの利用サンプル
    /// </summary>
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// ボタン押下時に並行実行可能な処理をマルチスレッドで実行する
        /// ※private void → private async void に変更
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void button1_Click(object sender, EventArgs e)
        {
            Console.WriteLine("最初に行う処理。これが終わるまではMainSampleは呼び出されない。");

            //マルチスレッド処理(awaitを付けて、メソッド内の処理が終わるのを待っている)
            await MainSample();

            Console.WriteLine("最後に行う処理。MainSampleが終わった後に呼び出される。");
        }

        /// <summary>
        /// 並行実行可能な処理
        /// ※private void → private async Task に変更
        /// </summary>
        /// <returns></returns>
        private async Task MainSample()
        {
            //task1の実行を開始
            Task<string> task1 = Dummy(5, "task1");

            //task2の実行を開始
            Task<string> task2 = Dummy(1, "task2");

            //task1とtask2の実行が終わるまで待つ
            await task1;
            await task2;

            //それぞれのtaskの戻り値を取得
            Console.WriteLine("task1の戻り値:" + task1.Result);
            Console.WriteLine("task2の戻り値:" + task2.Result);
        }
        
        /// <summary>
        /// 複数の引数を受け取り、処理結果を戻り値として返す
        /// ※private void → private async Task<string> に変更。戻り値が不要の場合は、private async Task にする。
        /// </summary>
        /// <param name="i"></param>
        /// <param name="s"></param>
        /// <returns></returns>
        private async Task<string> Dummy(int i, string s)
        {
            Console.WriteLine("処理開始:" + i);

            string dummyText = await Task.Run(() =>
            {
                //何らかの重い処理・・・
                System.Threading.Thread.Sleep(1000 * i);
                return s + "の処理完了:" + DateTime.Now.ToString();
            });

            Console.WriteLine("処理完了:" + i);

            return dummyText;
        }
    }
}

実行結果> 続きを読む 【C#】async/awaitを利用したマルチスレッド実装テンプレート

【Inno Setup】Inno Setup Scripts(*.iss)ファイルテンプレート

Inno Setupの記述サンプルです。
以下の例では、EXEとReadme.txtがインストーラに含まれます。
実際のパス、アプリ名称などを修正して利用してください。

尚、必ず[Setup]のAppIdは、Inno Setup Compilerのメニューから、Tools→Generate GUIDをクリックして出力された値に書き換えてから利用してください。

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
; Compiler Version 5.5.3(a)

#define MyAppName "アプリ名"
#define MyAppVersion "1.00"
#define MyAppPublisher "hoge-hoge"
#define MyAppURL "https://hoge.hoge/"
#define MyAppExeName "hoge.exe"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{95178216-BEFD-4EB7-B98B-C75CEC7E495B}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes

[Languages]
Name: "japanese"; MessagesFile: "compiler:LanguagesJapanese.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "C:アプリhoge.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:アプリReadme.txt"; DestDir: "{app}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}{#MyAppName}"; Filename: "{app}{#MyAppExeName}"
Name: "{commondesktop}{#MyAppName}"; Filename: "{app}{#MyAppExeName}"; Tasks: desktopicon

[Run]
Filename: "{app}{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

【Windows Bat】バッチファイル(*.bat)テンプレート

動作可能なバッチのサンプルが中々ないため作成。

このテンプレートをもとに目的のコマンド呼び出しを追加すれば、作業が捗る・・・かも。

@echo off
setlocal
rem **************************************************
rem Windowsバッチファイルテンプレート v1.01 2017/08/23
rem https://juraku-software.net/
rem ★印のブロックを書き換えて使ってください
rem 
rem このテンプレートの仕様>>
rem バッチファイルの保存フォルダの下にLogフォルダを作成し、そこに日付のログファイルを作成する。
rem エラー処理のテンプレも兼ねて故意に誤ったパラメータを指定してPingコマンドを実行している。
rem **************************************************

rem ■ログファイル名取得(現在時刻)
set TIME2=%time: =0%
set NOW_DATE=%date:~0,4%%date:~5,2%%date:~8,2%_%TIME2:~0,2%%TIME2:~3,2%%TIME2:~6,2%
set LOG_NAME=Log\%NOW_DATE%.log

rem ■カレントディレクトリ変更
cd /d %~dp0

rem ■ログ作成
if not exist Log\ (
 mkdir Log
)
echo バッチ起動 %date% %time% > %LOG_NAME%

rem ■目的のコマンド★
echo コマンド開始 >> %LOG_NAME%
rem エラーを起こすために適当なパラメータを指定
ping -aaa >> %LOG_NAME% 2>&1

rem ■エラー判定
if %errorlevel% == 0 (
 rem エラー無し
 echo コマンド実行成功 戻り値:%errorlevel% >> %LOG_NAME%
 endlocal
 exit /b 0
) else (
 rem エラー有り
 echo コマンド実行失敗 戻り値:%errorlevel% >> %LOG_NAME%
 endlocal
 exit /b %errorlevel%
)

rem ■終了

変更履歴
2017/08/23 setlocal~endlocalの記載追加

【WordPress】W3 Total Cache導入後、500エラー

W3 Total Cache導入後、大半のページが500エラー(500 Error CGI もしくは SSI が正しく動作していません。)になってしまう現象が発生しました。
プラグインを無効化しようとしても、ログインページが500エラーになってしまい何もできない状態となり、とても困りました。

環境:WordPress 4.7.1、ロリポップ

以下のサイトを参考に、FTPにて.htaccessのコメントアウトと、各ファイルをリネームしたところ、ログインページを含め500エラーが解消されました。ありがとうございます。
wpXレンタルサーバーでW3 Total Cacheが500エラーになる問題の解消方法、ピンチから脱出方法!

ただ、その後もダッシュボードに以下のエラーが出続けたため、記載されたパスのファイルもリネームしたところ、エラーが消え復旧しました。
W3 Total Cache Error: some files appear to be missing or out of place. Please re-install plugin or remove /xxxxx/wp-content/db.php.
W3 Total Cache Error: some files appear to be missing or out of place. Please re-install plugin or remove /xxxxx/wp-content/object-cache.php.

結局、よく原因が分からず。管理画面からプラグイン削除はできませんでしたが、今のところ問題なくサイト閲覧ができている状態ですので、様子を見ようと思います。

WordPressはプラグインを気軽に導入できてとても便利ですが、トラブルが発生した場合の解決方法を見つけるのは大変かもしれませんね。

【Access】レポートの数値項目の小数点以下表示桁数を自動で変更する

  1. テキストボックスのコントロールソースを以下の通りに変更
    =Format([フィールド名],IIf(Int([フィールド名])=[フィールド名],”#,##0″,”#,##0.####”))
  2. テキストボックスの書式を設定しない(空白に)
  3. テキストボックスの小数点以下表示桁数を「自動」に変更
  4. テキストボックスの文字配置を「右」に変更

動作結果

※Access2010にて動作確認