mineo 注意事項

基本事項
  • 余った通信容量は翌月まで持ち越し可能
  • 基本データ容量変更は、25 日までに行えば翌月から適用。26 日から月末の間は変更不可
  • 解約処理可能な時間帯は、9-21 時
フリータンク
  • 利用可能期間は、21 日から月末の前日まで
  • 大利用回数は月 2 回まで
  • 最大引き出し可能サイズは合計 1G まで
  • 引き出した分も、翌月繰越可能
  • 最大預け入れ可能サイズは合計 10G まで
パケットシェア
  • 解散すると、パケットシェア分の残容量はリーダーに集まるらしい
  • リーダー変更するには、一度解散するしかない
  • メンバー追加は月末日 23:30 までに承認が完了すると、翌月より適用。削除および解散は、承認が完了すると即時適用
  • 翌月から適用と言うのは、翌月からパケットシェアが使用可能になると言うことなので、注意(翌月にメンバーとして加わり、実際にシェアが行えるのが翌々月からになるわけではない)
マイネ王
  • コイン使用などは、eoID 連携している回線が対象になる。フリータンクの利用も同様。
  • eoID 連携回線の変更は、たぶんいつでも自由に出来る。(変更は簡単なので、あまり手間を気にする必要はない)

Azure Web Apps の環境変数例

Azure Web Apps では、自分で追加して使えるアプリ設定と同様、環境変数も動作環境の情報として取得して使うことが出来る。 参考のために、環境変数を全部出力した場合の例を記載する。

確認環境
  • 確認に使用したアプリ: ASP.NET MVC (.NET Framework) アプリを VS から発行
  • App Service プラン: S1
  • デプロイ Web サイト名 (一部マスク済み): WebAppTestxxxxx
  • デプロイスロット名: testSlotName スロット
  • アプリ設定に追加した内容: testKey = AppPortal!!!
出力例の中で使いそうな環境変数

Azure runtime environment · projectkudu/kudu Wiki · GitHub

  • WEBSITE_CURRENT_STAMPNAME = waws-prod-ty1-009
  • WEBSITE_INSTANCE_ID = 8fc0ce360d597bb860e4753e8dc8660a3255c7cf722763756dcd2648e3fxxxxx

スタンプ名は、デプロイ先スタンプ (利用 IP) が変わったか、判断できそう(?)。

インスタンス ID は、複数インスタンスで実行している場合、各インスタンスの判別に使えそう。

ConfigurationManager.AppSettings
aspnet:DisableFcnDaclRead = true
aspnet:PortableCompilationOutput = true
aspnet:PortableCompilationOutputSnapshotType = Microsoft.Web.Compilation.Snapshots.SnapshotHelper, Microsoft.Web.Compilation.Snapshots, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
ClientValidationEnabled = true
REMOTEDEBUGGINGVERSION = 15.0.28010.00
ScmType = None
testKey = AppPortal!!!!!
UnobtrusiveJavaScriptEnabled = true
webpages:Enabled = false
webpages:Version = 3.0.0.0
WEBSITE_AUTH_ENABLED = False
WEBSITE_NODE_DEFAULT_VERSION = 6.9.1
WEBSITE_SITE_NAME = webapptestxxxxx
Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process)
ALLUSERSPROFILE = D:\local\ProgramData
APP_POOL_CONFIG = C:\DWASFiles\Sites\WebAppTestxxxxx\Config\applicationhost.config
APP_POOL_ID = WebAppTestxxxxx
APPDATA = D:\local\AppData
APPSETTING_REMOTEDEBUGGINGVERSION = 15.0.28010.00
APPSETTING_ScmType = None
APPSETTING_testKey = AppPortal!!!!!
APPSETTING_WEBSITE_AUTH_ENABLED = False
APPSETTING_WEBSITE_NODE_DEFAULT_VERSION = 6.9.1
APPSETTING_WEBSITE_SITE_NAME = webapptestxxxxx
AZURE_JETTY9_CMDLINE = -Djava.net.preferIPv4Stack=true -Djetty.port=%HTTP_PLATFORM_PORT% -Djetty.base="D:\Program Files (x86)\jetty-distribution-9.1.0.v20131115" -Djetty.webapps="d:\home\site\wwwroot\webapps" -jar "D:\Program Files (x86)\jetty-distribution-9.1.0.v20131115\start.jar" etc\jetty-logging.xml
AZURE_JETTY9_HOME = D:\Program Files (x86)\jetty-distribution-9.1.0.v20131115
AZURE_JETTY93_CMDLINE = -Djava.net.preferIPv4Stack=true -Djetty.port=%HTTP_PLATFORM_PORT% -Djetty.base="D:\Program Files (x86)\jetty-distribution-9.3.25.v20180904" -Djetty.webapps="d:\home\site\wwwroot\webapps" -jar "D:\Program Files (x86)\jetty-distribution-9.3.25.v20180904\start.jar" etc\jetty-logging.xml
AZURE_JETTY93_HOME = D:\Program Files (x86)\jetty-distribution-9.3.25.v20180904
AZURE_TOMCAT7_CMDLINE = -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-7.0.50\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-7.0.50\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-7.0.50\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-7.0.50" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT7_HOME = D:\Program Files (x86)\apache-tomcat-7.0.50
AZURE_TOMCAT8_CMDLINE = -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-8.0.23\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-8.0.23\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-8.0.23\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-8.0.23" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT8_HOME = D:\Program Files (x86)\apache-tomcat-8.0.23
AZURE_TOMCAT85_CMDLINE = -noverify -Djava.net.preferIPv4Stack=true -Dcatalina.instance.name=%WEBSITE_INSTANCE_ID% -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-8.5.37\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-8.5.37\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-8.5.37\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-8.5.37" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT85_HOME = D:\Program Files (x86)\apache-tomcat-8.5.37
AZURE_TOMCAT90_CMDLINE = -noverify -Djava.net.preferIPv4Stack=true -Dcatalina.instance.name=%WEBSITE_INSTANCE_ID% -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-9.0.14\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-9.0.14\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-9.0.14\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-9.0.14" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT90_HOME = D:\Program Files (x86)\apache-tomcat-9.0.14
CommonProgramFiles = D:\Program Files (x86)\Common Files
CommonProgramFiles(x86) = D:\Program Files (x86)\Common Files
CommonProgramW6432 = D:\Program Files\Common Files
COMPUTERNAME = RD0003FF7xxxxx
ComSpec = D:\Windows\system32\cmd.exe
DOTNET_HOSTING_OPTIMIZATION_CACHE = D:\DotNetCache
HOME = D:\home
HOME_EXPANDED = C:\DWASFiles\Sites\WebAppTestxxxxx\VirtualDirectory0
JAVA_HOME = D:\Program Files\Java\zulu8.31.0.2-jre8.0.181-win_x64
LOCAL_EXPANDED = C:\DWASFiles\Sites\WebAppTestxxxxx
LOCALAPPDATA = D:\local\LocalAppData
NUMBER_OF_PROCESSORS = 1
OS = Windows_NT
Path = D:\Program Files (x86)\nodejs\6.9.1;D:\Windows\system32;D:\Windows;D:\Windows\System32\Wbem;D:\Windows\System32\WindowsPowerShell\v1.0\;D:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;;D:\Program Files (x86)\dotnet;D:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps;D:\Program Files (x86)\Git\cmd;D:\Program Files (x86)\PHP\v5.6;D:\Python27;
PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW
PROCESSOR_ARCHITECTURE = x86
PROCESSOR_ARCHITEW6432 = AMD64
PROCESSOR_IDENTIFIER = Intel64 Family 6 Model 63 Stepping 2, GenuineIntel
PROCESSOR_LEVEL = 6
PROCESSOR_REVISION = 3f02
ProgramData = D:\local\ProgramData
ProgramFiles = D:\Program Files (x86)
ProgramFiles(x86) = D:\Program Files (x86)
ProgramW6432 = D:\Program Files
PSModulePath = D:\Program Files\WindowsPowerShell\Modules;D:\Windows\system32\WindowsPowerShell\v1.0\Modules;D:\Program Files\WindowsPowerShell\Modules\;D:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\;D:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ServiceManagement\;D:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\Storage\;D:\Program Files\Microsoft Message Analyzer\PowerShell\
PUBLIC = D:\Users\Public
REGION_NAME = Japan East
REMOTEDEBUGGINGBITVERSION = vx86
REMOTEDEBUGGINGPORT = 
REMOTEDEBUGGINGVERSION = 15.0.28010.00
ScmType = None
SITE_BITNESS = x86
SystemDrive = D:
SystemRoot = D:\Windows
TEMP = D:\local\Temp
testKey = AppPortal!!!!!
TMP = D:\local\Temp
USERDOMAIN = WORKGROUP
USERNAME = RD0003FF7xxxxx$
USERPROFILE = D:\local\UserProfile
WEBSITE_AUTH_ENABLED = False
WEBSITE_AUTH_ENCRYPTION_KEY = 8A8EB5DC5E411303CA82B4F7D1BA756D5AE7D172E0B78CA1100E348465Cxxxxx
WEBSITE_AUTH_SIGNING_KEY = EEAF022FD42956BEF9C8B5013B354BF8A9F125052A2F95FA5A001E06CEFxxxxx
WEBSITE_COMPUTE_MODE = Dedicated
WEBSITE_CONFIGURATION_READY = 1
WEBSITE_CONTAINER_READY = 1
WEBSITE_CURRENT_STAMPNAME = waws-prod-ty1-009
WEBSITE_DYNAMIC_CACHE = 1
WEBSITE_ELASTIC_SCALING_ENABLED = 0
WEBSITE_FRAMEWORK_JIT = 1
WEBSITE_HOME_STAMPNAME = waws-prod-ty1-009
WEBSITE_HOSTNAME = webapptestxxxxx.azurewebsites.net
WEBSITE_HTTPLOGGING_ENABLED = 0
WEBSITE_IIS_SITE_NAME = WebAppTestxxxxx
WEBSITE_INSTANCE_ID = 8fc0ce360d597bb860e4753e8dc8660a3255c7cf722763756dcd2648e3fxxxxx
WEBSITE_LOCALCACHE_ENABLED = False
WEBSITE_NODE_DEFAULT_VERSION = 6.9.1
WEBSITE_OWNER_NAME = xxxxx+WebAppTestxxxxx-JapanEastwebspace
WEBSITE_PROACTIVE_AUTOHEAL_ENABLED = True
WEBSITE_RELAYS = 
WEBSITE_RESOURCE_GROUP = webapptestxxxxx
WEBSITE_REWRITE_TABLE = 
WEBSITE_SCM_ALWAYS_ON_ENABLED = 0
WEBSITE_SCM_SEPARATE_STATUS = 1
WEBSITE_SITE_NAME = webapptestxxxxx
WEBSITE_SKU = Standard
WEBSITE_VOLUME_TYPE = PrimaryStorageVolume
WEBSOCKET_CONCURRENT_REQUEST_LIMIT = -1
windir = D:\Windows
windows_tracing_flags = 
windows_tracing_logfile = 
XENON = 0
Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine)
AZURE_JETTY9_CMDLINE = -Djava.net.preferIPv4Stack=true -Djetty.port=%HTTP_PLATFORM_PORT% -Djetty.base="D:\Program Files (x86)\jetty-distribution-9.1.0.v20131115" -Djetty.webapps="d:\home\site\wwwroot\webapps" -jar "D:\Program Files (x86)\jetty-distribution-9.1.0.v20131115\start.jar" etc\jetty-logging.xml
AZURE_JETTY9_HOME = D:\Program Files (x86)\jetty-distribution-9.1.0.v20131115
AZURE_JETTY93_CMDLINE = -Djava.net.preferIPv4Stack=true -Djetty.port=%HTTP_PLATFORM_PORT% -Djetty.base="D:\Program Files (x86)\jetty-distribution-9.3.25.v20180904" -Djetty.webapps="d:\home\site\wwwroot\webapps" -jar "D:\Program Files (x86)\jetty-distribution-9.3.25.v20180904\start.jar" etc\jetty-logging.xml
AZURE_JETTY93_HOME = D:\Program Files (x86)\jetty-distribution-9.3.25.v20180904
AZURE_TOMCAT7_CMDLINE = -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-7.0.50\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-7.0.50\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-7.0.50\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-7.0.50" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT7_HOME = D:\Program Files (x86)\apache-tomcat-7.0.50
AZURE_TOMCAT8_CMDLINE = -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-8.0.23\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-8.0.23\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-8.0.23\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-8.0.23" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT8_HOME = D:\Program Files (x86)\apache-tomcat-8.0.23
AZURE_TOMCAT85_CMDLINE = -noverify -Djava.net.preferIPv4Stack=true -Dcatalina.instance.name=%WEBSITE_INSTANCE_ID% -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-8.5.37\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-8.5.37\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-8.5.37\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-8.5.37" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT85_HOME = D:\Program Files (x86)\apache-tomcat-8.5.37
AZURE_TOMCAT90_CMDLINE = -noverify -Djava.net.preferIPv4Stack=true -Dcatalina.instance.name=%WEBSITE_INSTANCE_ID% -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util.logging.config.file="D:\Program Files (x86)\apache-tomcat-9.0.14\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dsite.logdir="d:/home/LogFiles/" -Dsite.tempdir="d:\home\site\workdir" -classpath "D:\Program Files (x86)\apache-tomcat-9.0.14\bin\bootstrap.jar;D:\Program Files (x86)\apache-tomcat-9.0.14\bin\tomcat-juli.jar" -Dcatalina.base="D:\Program Files (x86)\apache-tomcat-9.0.14" -Djava.io.tmpdir="d:\home\site\workdir" org.apache.catalina.startup.Bootstrap
AZURE_TOMCAT90_HOME = D:\Program Files (x86)\apache-tomcat-9.0.14
ComSpec = D:\Windows\system32\cmd.exe
DOTNET_HOSTING_OPTIMIZATION_CACHE = D:\DotNetCache
NUMBER_OF_PROCESSORS = 1
OS = Windows_NT
Path = D:\Program Files (x86)\nodejs\6.9.1;D:\Windows\system32;D:\Windows;D:\Windows\System32\Wbem;D:\Windows\System32\WindowsPowerShell\v1.0\;D:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;;D:\Program Files (x86)\dotnet;D:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps;D:\Program Files (x86)\Git\cmd;D:\Program Files (x86)\PHP\v5.6;D:\Python27;
PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW
PROCESSOR_ARCHITECTURE = x86
PROCESSOR_IDENTIFIER = Intel64 Family 6 Model 63 Stepping 2, GenuineIntel
PROCESSOR_LEVEL = 6
PROCESSOR_REVISION = 3f02
PSModulePath = D:\Program Files\WindowsPowerShell\Modules;D:\Windows\system32\WindowsPowerShell\v1.0\Modules;D:\Program Files\WindowsPowerShell\Modules\;D:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ResourceManager\AzureResourceManager\;D:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ServiceManagement\;D:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\Storage\;D:\Program Files\Microsoft Message Analyzer\PowerShell\
TEMP = D:\local\Temp
TMP = D:\local\Temp
USERNAME = RD0003FF7xxxxx$
windir = D:\Windows
Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)
Path = D:\Program Files (x86)\nodejs\6.9.1;D:\Windows\system32;D:\Windows;D:\Windows\System32\Wbem;D:\Windows\System32\WindowsPowerShell\v1.0\;D:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;;D:\Program Files (x86)\dotnet;D:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps;D:\Program Files (x86)\Git\cmd;D:\Program Files (x86)\PHP\v5.6;D:\Python27;
TEMP = D:\local\Temp
TMP = D:\local\Temp
Environment.GetEnvironmentVariable("WEBSITE_COUNTERS_ALL")

環境変数の一覧には現れないが、変数名を直接指定すると取得できる隠し環境変数らしい。詳細は下記。

{
  "aspNet": {
    "applicationRestarts": 0,
    "applicationsRunning": 0,
    "requestsDisconnected": 0,
    "requestExecutionTime": 11,
    "requestsRejected": 0,
    "requestsQueued": 0,
    "wpsRunning": 0,
    "wpsRestarts": 0,
    "requestWaitTime": 0,
    "requestsCurrent": 1,
    "globalAuditSuccess": 12,
    "globalAuditFail": 0,
    "globalEventsError": 0,
    "globalEventsHttpReqError": 0,
    "globalEventsHttpInfraError": 0,
    "requestsInNativeQueue": 0,
    "anonymousRequests": 6,
    "totalCacheEntries": 18,
    "totalCacheTurnoverRate": 234,
    "totalCacheHits": 227,
    "totalCacheMisses": 149,
    "totalCacheRatioBase": 376,
    "apiCacheEntries": 6,
    "apiCacheTurnoverRate": 10,
    "apiCacheHits": 8,
    "apiCacheMisses": 6,
    "apiCacheRatioBase": 14,
    "outputCacheEntries": 0,
    "outputCacheTurnoverRate": 0,
    "outputCacheHits": 0,
    "outputCacheMisses": 0,
    "outputCacheRatioBase": 0,
    "compilations": 0,
    "debuggingRequests": 0,
    "errorsPreProcessing": 0,
    "errorsCompiling": 0,
    "errorsDuringRequest": 0,
    "errorsUnhandled": 0,
    "errorsTotal": 0,
    "pipelines": 1,
    "requestBytesIn": 0,
    "requestBytesOut": 274840,
    "requestsExecuting": 1,
    "requestsFailed": 0,
    "requestsNotFound": 0,
    "requestsNotAuthorized": 0,
    "requestsInApplicationQueue": 0,
    "requestsTimedOut": 0,
    "requestsSucceded": 5,
    "requestsTotal": 6,
    "sessionsActive": 1,
    "sessionsAbandoned": 0,
    "sessionsTimedOut": 0,
    "sessionsTotal": 1,
    "transactionsAborted": 0,
    "transactionsCommitted": 0,
    "transactionsPending": 0,
    "transactionsTotal": 0,
    "sessionStateServerConnections": 0,
    "sessionSqlServerConnections": 0,
    "eventsTotal": 13,
    "eventsApp": 1,
    "eventsError": 0,
    "eventsHttpReqError": 0,
    "eventsHttpInfraError": 0,
    "eventsWebReq": 0,
    "auditSuccess": 12,
    "auditFail": 0,
    "memberSuccess": 0,
    "memberFail": 0,
    "formsAuthSuccess": 0,
    "formsAuthFail": 0,
    "viewstateMacFail": 0,
    "appRequestExecTime": 11,
    "appRequestDisconnected": 0,
    "appRequestsRejected": 0,
    "appRequestWaitTime": 0,
    "cachePercentMachMemLimitUsed": 53,
    "cachePercentMachMemLimitUsedBase": 97,
    "cachePercentProcMemLimitUsed": 659,
    "cachePercentProcMemLimitUsedBase": 1100728,
    "cacheTotalTrims": 0,
    "cacheApiTrims": 0,
    "cacheOutputTrims": 0,
    "appCpuUsed": 0,
    "appCpuUsedBase": 0,
    "appMemoryUsed": 0,
    "requestBytesInWebsockets": 0,
    "requestBytesOutWebsockets": 0,
    "requestsExecutingWebsockets": 0,
    "requestsFailedWebsockets": 0,
    "requestsSucceededWebsockets": 0,
    "requestsTotalWebsockets": 0
  },
  "app": {
    "userTime": 27656250,
    "kernelTime": 10781250,
    "pageFaults": 55355,
    "processes": 1,
    "processLimit": 0,
    "threads": 26,
    "threadLimit": 0,
    "connections": 0,
    "connectionLimit": 0,
    "sections": 0,
    "sectionLimit": 0,
    "namedPipes": 1,
    "namedPipeLimit": 128,
    "readIoOperations": 508,
    "writeIoOperations": 24,
    "otherIoOperations": 10061,
    "readIoBytes": 1406619,
    "writeIoBytes": 34258,
    "otherIoBytes": 289032,
    "privateBytes": 62025728,
    "handles": 725,
    "contextSwitches": 6856,
    "remoteOpens": 29,
    "remoteWrites": 0,
    "remoteWriteKBs": 0,
    "availMemoryBytes": 853381120,
    "remoteDirMonitors": 1,
    "remoteDirMonitorLimit": 0,
    "activeConnections": 0,
    "activeConnectionLimit": 0
  },
  "clr": {
    "bytesInAllHeaps": 0,
    "gcHandles": 0,
    "gen0Collections": 0,
    "gen1Collections": 0,
    "gen2Collections": 0,
    "inducedGC": 0,
    "pinnedObjects": 0,
    "committedBytes": 0,
    "reservedBytes": 0,
    "timeInGC": 0,
    "timeInGCBase": 0,
    "allocatedBytes": 0,
    "gen0HeapSize": 0,
    "gen1HeapSize": 0,
    "gen2HeapSize": 0,
    "largeObjectHeapSize": 0,
    "currentAssemblies": 0,
    "currentClassesLoaded": 0,
    "exceptionsThrown": 0,
    "appDomains": 0,
    "appDomainsUnloaded": 0
  }
}

Azure App Service で Azure PowerShell を使う

ちゃんと動作確認したのは Azure Functions だけど、基本的には Azure App Service の制限の話のはずなので、Web Apps とかでも考え方は同じはず。

Azure Functions で Automation 使用して .NET から Azure PowerShell を使う場合、考慮が必要なのは下記 3 点。

それぞれ詳細を以下に説明する。

PowerShell 本体のバージョンについて

App Service は PaaS なので、.NET ランタイムと同じく PowerShell 本体のバージョンを開発者が選ぶことはできない。 2019/4 現在は、以下のように 5.1 がインストールされている様子(Kudu で確認)。

> $PSVersionTable

f:id:poke_dev:20190429151019p:plain

上記より古い想定は不要と思うが、最新の PowerShell で実装された機能など使っている場合は、ローカルでは動くのに Azure に上げたら動かないという可能性がありえるので、Azure 上のバージョンで問題ないかは早めに確認しておくのが無難。

2018 年までは結構古い 4.0 でバージョンが止まっていたので、必ずしも最新のバージョンがインストールされるとは限らないことに注意。

Azure PowerShell のバージョンについて

PowerShell 本体のバージョンと異なり、App Service VM 上にインストールされている Azure PowerShell のバージョンは恐ろしいほど低く、2019/4 現在は、以下のようにバージョン 1.4 となっている。

> Get-Module -ListAvailable -Name Azure -Refresh

f:id:poke_dev:20190429155226p:plain

利用する内容にもよるとは思うが、基本的には古すぎて、これを利用するのは現実的ではないと思われる。 PowerShell 本体同様、PaaS なので VM イメージに含まれる上記ライブラリをアップデートするのは無理なのだが、対策はある。

Question: Azure Powershell Scripts in a Function · Issue #294 · Azure/Azure-Functions · GitHub

詳細は上記サイトを確認してもらいたいが、要は、

  1. 対象 Auzre PowerShell モジュールをフォルダごと App Service のフォルダにアップロード
  2. プログラムでは、1 でアップロードした psd1 モジュールを Global パラメータ付きでインポート
  3. 通常通り、Azure PowerShell のコマンドを使用

となる。当該モジュールは Kudu でアップロードして使用するのももちろん可能だが、Functions などのプロジェクトで使用するのであれば、プロジェクトの静的ファイルに当該モジュールを含めて、プロジェクトのデプロイ時に Auzre PowerShell のライブラリも一緒にデプロイされるようにした方が、デプロイが楽になると思われる。

また、そうすることでローカルでも Azure でも常に同じバージョンの Azure PowerShell を使うことになるので、ローカルと Azure で動作に差異が発生する可能性が抑えられる。

PowerShell の実行権限について

.NET の Automation で PowerShell を使用する場合は、PowerShell 実行権限の変更が必要になる。詳細は下記参照。

C# から実行権限が必要な PowerShell を実行する - poke_dev’s blog

RDManager (旧 RDReserveChecker)

東芝のHDDレコーダー、DBR-Z260、RD-X9、RD-X7 もしくは RD-X6 と連携させて使用するソフト。

主な機能

  • RD 録画予約一覧の取得
  • テレビ王国番組表からの番組データ取得と、録画予約一覧との突き合わせ
  • キーワードなどの条件を入力しての番組データ検索
  • 録画予約の実行フラグ変更、録画予約削除
  • 録画済タイトルの検索と、格納フォルダ移動

f:id:poke_dev:20190420182651p:plain

重要事項

このソフトを使用して発生したいかなる損害に対しても、一切責任を負いません。使用は自己責任でお願いします。 再配布は禁止とします。 対応できるかどうかは分かりませんが、 バグや要望がありましたら shingonATTOmbr.nifty.com(お手数ですがATTOを@に置き換えてください)までメールいただくか、Twitter で @poke_dev までお知らせください。

なお、2019/4/20 現在、まだメンテナンスはしていますが、2013 年ぐらいから基本的にはもう延命の状態に入っているので、新機能追加などはありません。 特に、番組表データについてはテレビ王国番組表に依存しているため、このサイトから取得できなくなったら、終わりの可能性が高いです。

使用方法

RD対応機種

動作確認をしている機種は、当初は『DBR-Z260』『RD-X9』『RD-X7』および『RD-X6』でしたが、現在は DBR-Z260 のみです。ネットdeナビの仕様(バージョン2)の関係で、これ以外、少なくともRD-X6より古い機種で動く可能性はないと思います。

また、RDのバージョンによってネットdeナビの機能にも差異があるため、本ツールで行える処理にも差異があります。特にX9では録画予約に関する機能として参照以外の機能が削除されたため、本ツールも影響を受けています。 新規の録画予約については以前の機種とほぼ同様の方法で処理を行っていますが、既存録画予約の実行フラグ変更と削除については、ネットdeリモコンを使用した方法で対処しています。 要は、普通にリモコンで操作して行う作業を自動化して対処しているので、ネットdeナビの機能を使用する方法と比較すると、不安定感が否めないです。 また、実行するにあたり制限も多いため、RDが起動していても処理が行えない場合があります。 DBR-Z260 では以前のネットdeナビ機能が復活していたので、そちらを使用するようにしています。

動作環境

現在は Windows 10 でしか動作確認していません。 最新バージョンでは .NET 4.5 を使用しているため、最低でも Windows 7 以上でないと動作しないはずです。

必要な.NET Frameworkがインストールされていない場合は、EXE起動時にエラーが出ると思いますので、適宜 .NET Framework のインストールを行ってください。

ダウンロード

以下のリンク先からダウンロードして下さい。

https://hatenablob.blob.core.windows.net/pub/rdmanager/RDManager.zip

v0.63.0.0 - 2021/10/02

前バージョンへ上書きコピーを行う場合の特記事項

なし。上書きコピーでいけるはずです。

インストール及びアンインストール

ダウンロードした圧縮ファイルを解凍するだけです。 レジストリなどは使用していないので、アンインストールもフォルダごと削除するだけです。

RDManager.exe の実行時に以下のような警告が表示される場合は、

f:id:poke_dev:20190420224503p:plain

ファイルのプロパティを表示して、[ブロックの解除] ボタンを押下して、ブロックを解除してください。

f:id:poke_dev:20190420224529p:plain

このソフトの使用方法

このソフトを使用するには最初に環境設定が必要になります。 環境設定が行われていない場合はソフト起動時に環境設定ダイアログが表示されるので、適宜設定を行ってください。 メニューから辿る場合は[オプション] - [環境設定]を選択してください。

f:id:poke_dev:20190420224927p:plain

環境設定の「RD識別名」はプログラム内のキーに直接使用しているため、全角文字やスペースとかが含まれると、マズイかもしれません。 この辺りはチェックしていませんが、半角英数字記号のみで構成していただければ基本的に問題ありません。 「RD種別」の設定もプログラムの処理に直接影響するため、適切な項目を選択してください。 自分が所有・検証している RD を項目に含めていますが、結局のところ、ネットdeナビやネットdeリモコンの仕様の差異を吸収するための設定なので、選んだ設定値と対象機種の仕様が近ければ他の機種でも動作するかもしれません。

上記環境設定に加え、番組表データを取得するために、RD のチャンネルコードとテレビ王国番組表のチャンネル名のマッピングを設定する必要がありますので、こちらもチャンネルマッピングダイアログで設定してください。

設定が終了していれば、メニューバーの[データ] - [RD録画予約一覧の取得]で RD の録画予約一覧を取得できます。 また、同じくメニューバーの[データ] - [番組表データの取得]で、番組表データの取得が行えます。 ツールバーの「録画予約をチェックする」ボタンを押すと、上記 2 動作を連続して行います。

注意:できれば、このソフトを実行するのは録画が行われていない時にしてください。今のところこのソフトが原因で RD がフリーズすることはなるべくないように処理しているつもりですが、保障は全くできません(初期のバージョンでは実際にフリーズした事があります)。録画中の操作は危険度が高いです。

注意2:複数台対応は行いましたが、設定周りのチェックはあまりテストしてません。 環境設定の「RD識別名」がかなり重要となりますが、この設定値は、一度設定した後は基本的に変更しないでください。 変更しても構いませんが、この設定値は既存データのキーとなっていて、変更時の付け替え処理なども行っていないので、 変更時は既存データが使えなくなります。 また、登録した順にツールバーに RD の識別名ボタンが表示されますが、この順番を変更するような仕組みは今のところもっていないので、 最後に追加した RD の設定を一番初めにもってきたいなど順番の変更が必要な場合は、Setting フォルダに存在する RDSetting.xml ファイルをエディタなどで直接変更して順番を入れ替えてください。 RDの設定を削除する機能もまだ実装していないので、削除が必要な場合も xml ファイルを直接編集してください。

メイン画面(予約関連)

RD の録画予約一覧とテレビ王国番組表との突合せ情報を表示します。 「タイトル」列のみ編集可能。「タイトル」には初期状態では RD の予約名が設定されています (あくまで初期値が設定されるだけであり、「予約名」とは異なることに注意してください。「タイトル」列はこのアプリ独自の管理項目です)。 表示列は任意の列が設定可能ですが、テレビ王国番組表との突合せ結果確認のため、少なくとも「予約開始時刻番組」列と「状態」列は表示する必要があると思います。 また、「タイトル」列を右クリックすると以下のようなコンテキストメニューが表示され、選択タイトルを基にした操作が行えます。

f:id:poke_dev:20190420225307p:plain

RD に対して状態チェックを行い、各状態は色で分けていますが、青が稼働中、黄色が DEPGT、赤が電源断を示しています。 録画予約を行うことが可能かなども、この状態を基に判定しています。

f:id:poke_dev:20190420225329p:plain

それと、ツールバーのボタン上に録画予約残時間およびタイトル数の警告アイコンを表示するようにしています。 上記イメージ例だと、RD-X9 は問題なしで、RD-X7 は残時間かタイトル数がやばい事、 RD-X6 は情報が取得できておらず不明であることを示しています。 後、「録画予約同時確認機能」の対象になっている RD も確認できるようにしています。 RD の状態パネルの下部(要はボタンの左下)に白いぽっちが表示されている場合、「録画予約同時確認機能」の対象になっていることを示しています。

RD-X9 に対しても既存録画予約の実行フラグ変更と削除が行えるようになっていますが、前述したように、ネットdeリモコンの機能を使用してリモコンの操作を自動化して対応しています。 そのため、一つでも操作が外れると予期しない結果が発生する可能性があります。各コマンド実行後の待ち時間については自分の X9 の状態で調整して値を出しているので、他の X9 でも適切な待機時間となっているかはわかりません。 恐らく本体で行っている処理や録画済みタイトル数なども影響すると思うのですが、その辺りについて正確に把握することはかなり困難です。対象とするX9でも本当に適切に動作するか、必ず初めに確認してください。 確認方法は、テレビで対象 RD の番組ナビを見れる状態にしてから、本アプリで実行フラグの変更や録画削除を行うだけです。 後は勝手に一連の操作が行われるので、正常に完了するか目視で確認してください。

チャンネルマッピング

ツールバーの [オプション] - [チャンネルマッピング] でチャンネルマッピングダイアログが表示されるので、 RD のチャンネルコード(表示CH)に対するテレビ王国番組表のチャンネル名を設定してください。

RD 側のチャンネルコードは本体の番組表またはネットdeナビ画面から確認できます(下記スクリーンショットの赤線部分)。 ただ、RD-X9 など機種によってはネットdeナビ画面の機能が削られている場合があるので、その場合は本体の番組表でチャンネルコードを確認してください。

番組表データのダウンロードは、ここで設定されているテレビ王国番組表チャンネル名について行います(下記スクリーンショットの青線部分)。 テレビ王国番組表のチャンネル名は、画面左の選択値に連動しています。

まとめると、以下のスクリーンショットの、赤線で囲まれた RD 側のチャンネルコードと、 青線で囲まれたテレビ王国番組表側のチャンネル名を正しく設定する必要があります。

デジタル放送かどうかのチェック列は、面倒かもしれませんが、それぞれ適切に設定を行ってください。

f:id:poke_dev:20190420225509j:plain

f:id:poke_dev:20190420225521p:plain

キーワード設定

録画予約一覧の「キーワード」列のボタンを押下することでキーワード設定ダイアログが表示されるので(右クリック時のコンテキストメニューからも表示可)、判定用のキーワードを設定してください。 タイトルとここでのキーワードが判定処理で使用されます。判定がうまくいっていない場合はキーワードの設定で調整してみてください。

f:id:poke_dev:20190420225613p:plain

番組表検索

取得した番組表データの検索が行えます。 キーワードに加え、ジャンル、新番組などの付加情報の指定も行えます。 右クリック時のコンテキストメニューから、録画予約や、番組タイトルでの Google 検索を行ったりすることができます。

新番組や再放送などのフラグは基本的に全てネットdeナビ番組表データに含まれる [新] などの情報を使用しているのですが、場合によってはこれらの情報以外からも判断したい時があるので、そのフラグを「新番組(拡)」として追加してます。 このフラグは、タイトルか番組内容詳細に「#1」「第1」「(1)」が含まれる場合にヒットします。 判定条件がルーズなため、拾ってほしくない番組もヒットすることが多いですが、必要に応じて使用してください。

f:id:poke_dev:20190420225649p:plain

お気に入り

「番組表検索」の条件設定を、個別に登録、保存しておける機能です。 検索条件にヒットした番組数と、そのうち実際に録画予約対象となっている番組数がタブ名の横に表示されます。 お気に入りタブを追加したい場合、一番右端のタブ名が空のタブをクリックしてください。

f:id:poke_dev:20190420225723p:plain

録画済タイトル一覧

画面左端のタブで切り替えられます。 録画済タイトルの表示および操作が行えます。録画予約一覧と異なり、処理対象にできる RD はツールバーで選択している一台のみです。

タイトル一覧取得時は、番組説明も一緒に取得します。 但し、キャッシュ機能があるため、未キャッシュの番組説明のみ自動的に取得されます。 なので、初回のみデータの取得に時間がかかりますが、2 回目以降はそこまで時間かからないはずです。 キャッシュ済みの番組説明については基本的に再度取得することはありませんが、「最新の番組説明を取得」チェックボックスにチェックをつけて録画済タイトルを取得することで、キャッシュ済みの番組説明も強制的に再取得します。 但し、番組説明を取得しない場合と比べて非常に時間がかかります。タイトルが444の状態では、番組説明を取得しない場合は 1 分程度、番組説明も取得する場合は 5 分半程かかりました。

フォルダの移動機能は複数タイトルを選択しての一括処理に対応してますので、まとめてゴミ箱へ移動することなども可能です(移動先は別にゴミ箱じゃなくてもOK)。 また、異なる記録先間のタイトル移動(例えば、本体 HDD から USB HDD への移動)はできません(ネットdeナビでそのような機能がないため)。 フォルダのツリー情報は自動的に情報更新することはしていないため、タイトルを移動した場合、タイトル数や録画時間などにずれが生じます。 リアルタイムに情報が反映されていないことを考慮して使ってください。 最新の状態を取得したい場合は、再度全タイトル取得を行ってください。

f:id:poke_dev:20190420225801p:plain

画面左のツリーで、「ルート」と表示されている項目がありますが、この項目に直接属するタイトルは、(このアプリケーションでは)実際にはありません。 そのため、「下位のフォルダ構造を無視」チェックボックスにチェックを付けていない場合、「ルート」を選択してもタイトルは表示されません。

全タイトルを取得した時のみ、記録先毎のタイトル数、チャプター数、記録時間を計算して表示します。 以下のようになっており、記録先、例えば HDD の項目名の後ろに、「ALL (T:338, C:1164) 234:16:33」と表示されていますが、これが記録先全体で見たときの情報となります。 T がタイトル数、C がチャプター数を表しています。 つまりこの例だと、HDD に記録されている総タイトル数が 338 タイトルで、総チャプター数が 1164 チャプターと言う事になります。

f:id:poke_dev:20190420225843p:plain

電源の ON、OFF について

電源 ON の機能については WOLWake On Lan)と言う方法で行っていて、その仕様上、電源 ON の命令が必ず RD に届くわけではありません。 ローカル LAN 内であれば届く可能性が高いですが、届かない場合もあります。 RD 起動後、「RDの状態」が更新されるまである程度のタイムラグがある事に注意してください。

電源 OFF の機能については、RD の状況によっては電源が切れない事があります。 例えば録画中に電源 OFF の命令を送っても電源は切れません。 この場合、画面にはその旨を知らせるメッセージが表示されているのですが、このソフトではそれを検知できません。

また、RD が DEPGT 中の場合は、このソフトによる電源の ON、OFF は行えません。 DEPGT の状態から電源 ON の状態に移行するにはリモコンもしくは本体のボタンにより直接電源を ON にするしかありません。

主に確認が取れてる録画予約やタイトル管理方法

  • 地上デジタル、BS デジタルの録画予約
  • 毎○曜日の予約
  • ライブラリ管理なし
  • タイトルは本体の HDD 上で管理
  • 上記のような録画予約はいつもやっているのでそれなりに動作確認が取れているが、 それ以外の録画予約方法となってしまうといったいどうなってしまうのか正直不明。

余談ですが、よく、「ネットdeナビからの予約だと、番組追っかけや延長の機能が有効にならないから、あまり使えない」 みたいな話をネット上で見かけます。 これらの必須機能はネットdeナビからの予約では有効にならないため、それだけ考えると確かにあまり使えないように思えてしまいますが、要は使い方によるかなと思っています。 本体から録画予約して、これらの機能を有効にした状態で録画予約するのがベストですが、本体から予約する時に一番ネックになるのが、「目的の番組を探すのが面倒」なところだと思っています。 そのため、自分の録画予約方法としては、次のように対応しています。

  1. このアプリで目的の番組を検索して予約を入れる
  2. RD 本体で、[番組ナビ] - [録画予約一覧] を表示する
  3. このアプリから予約した項目を選択して、リモコンの[黄]ボタンを押す
  4. 番組表が表示され、対象番組が既に選択された状態になっているので、後は通常通り、新規予約を入れる
  5. このアプリから入れた予約はもう不要なため、予約キャンセルする

要は、「このアプリから入れる予約は、本体での予約操作を楽にするためのダミー予約として入れる」と言うことになります。

ネットdeナビの情報について

状況としてはあまり多くないですが、ネットdeナビの情報と本体の情報が食い違っている場合があります。 本アプリケーションではネットdeナビの情報を扱うため、上記のような食い違いがあるとこのアプリケーションでも正しく表示できない可能性があります。 本アプリケーションの情報が何か変だと思ったら、ネットdeナビ、本体の情報を確認してください。

バージョン履歴

  • 2021/10/02 Ver 0.63.0.0 テレビ王国番組表サイトの仕様変更に対応 (番組属性情報のアイコン化解除対応)
  • 2021/04/29 Ver 0.62.0.0 テレビ王国番組表サイトの仕様変更に対応 (User Agent 対応)
  • 2019/04/20 Ver 0.61.0.0 テレビ王国番組表サイトの仕様変更に対応 (TLS 1.2 対応)
  • 2017/10/09 Ver 0.60.0.0 テレビ王国番組表サイトの仕様変更に対応
  • 2013/10/06 Ver 0.59.0.0 MSN TV 番組表サイトの終了に伴い、テレビ王国番組表に移行
  • 2013/04/21 Ver 0.58.0.0 DBR-Z260 に対応

Azure App Service のメモリ使用率について

App Service プランの Basic 以上は使用可能メモリの上限が決まっている。 同じ App Service プラン上に複数の Web Apps などを載せて使用することが出来るが、これはつまり、同じインスタンスのメモリを食い合っていることに他ならない。

例えば 5 個の Web App リソースを B1 プラン (メモリ 1.75GB) の同一 App Service プラン上に載せて、それぞれに素の ASP.NET MVC アプリをデプロイした場合、それぞれの Web App でワーカープロセスが動作しているのであれば、App Service としては大体 60% 前後のメモリ使用率が発生する。

App Service のアプリ設定には「常時接続」項目があり、これを「オフ」にするメリットは何なのかと思うかもしれない。 常時接続をオフにした場合、一定時間 (20 分) 使用されないとワーカープロセスが自動で終了するが、恐らく、上記のようにあまり使われない複数のアプリを同居させた際に使っていないアプリのワーカープロセスを落とすことで、複数アプリ同居時の効率を上げるためのオプションなのかと思う。なので、アプリを 1 つしか使っていないのであれば、常時接続をオフにするメリットは何もないと思われる。

以下は、上述した 1 つの B1 App Service に 5 個の Web Apps を載せた時のメモリ使用率の例。

f:id:poke_dev:20190407015637p:plain

最初に 55% まで上がり、その後、アプリを追加するごとにメモリ使用率が上昇して一度 65% ぐらいまで上がっている。 その後また 55% まで下がったのは、常時接続をオフにした後、アプリの再起動を行い、強制的にワーカープロセスを落としたため。 そこからまた 60% まで上昇しているのは、それぞれのアプリにアクセスしてワーカープロセスが起動したため。

ワーカープロセスが起動していなくても 55% までしかメモリ使用率が落ちないと言うか、そもそも最初の時点で 55% に達しているのがやや不思議だが、どうやらこれは、純粋なアプリの使用率ではなく、土台の OS も含めた使用率らしく、その部分で 55% (= 約 1GB) 常にもっていかれている様子。

Azure App Service Memory Usage. Where to see full breakdown? - Stack Overflow

以下は、アプリでのワーカープロセス使用がない状態で、Basic プランを B1 (1.75 GB) -> B2 (3.5 GB) -> B3 (7 GB) に上げていった際のメモリ使用率の変化。

f:id:poke_dev:20190407024343p:plain

それぞれのプランでの最低使用率が、B1 (54%) -> B2 (33%) -> B3 (20%) と低くなっていくことが分かる。 このパーセンテージで計算すると、プランを上げた際に最低使用量も B1 (950 MB), B2 (1.16 GB), B3 (1.4 GB) のように増加しているため、アプリ以外のメモリ消費量はプランによらず固定というわけでもない様子。

それぞれのプランでアプリが使用可能な残メモリを計算すると、B1 (800 MB), B2 (2.34 GB), B3 (5.6 GB) となるので、 アプリで使用可能なメモリ量 のみにフォーカスすると、プランが上がるほどお得になっている (CPU やその他リソースの事もあるので、メモリだけで一概にお得度は判断できないが)。

どうせなので、Basic, Standard, Premium (V1) についても B1 から P3 まで順に切り替えていってアプリのワーカープロセスなし状態のメモリ消費状況を確認してみたが、Basic, Standard, Premium 間で特に差異はなかった。

f:id:poke_dev:20190407134219p:plain

1.75 GB 3.5 GB 7 GB
B1 (52%) B2 (33%) B3 (20%)
S1 (51%) S2 (33%) S3 (21%)
P1 (51%) P2 (35%) P3 (20%)

稼働中 Azure Web Apps に影響を与える操作について (再起動とか)

Azure ポータルでは Web Apps に関して色々と操作出来るが、その際の稼働中 Web Apps の挙動について説明。 なお、Functions の挙動は異なるので注意 (https://poke-dev.hatenablog.com/entry/2019/11/24/160018)。

ここでは ASP.NET MVC のプロジェクト作成時の状態を Free/Basic プランの 1 インスタンス Web Apps で確認している。 Basic についても「常時接続」設定がオフの場合は、本件の確認内容については Free と本質的に差異はないはず。

また、Basic 以上のプランであれば 2 インスタンス以上にスケールアウトすることが可能だが、スケールアウト時は仮想マシン自体が増加するので、挙動の差異は特にないはず(同じ挙動が全インスタンスで同様に行われるだけ)。

なお、セッション情報の格納先が既定の InProc となっている場合は、ワーカープロセスの再起動やリサイクルでセッション情報も失われるので、注意。

Azure Web Apps + ASP.NET の環境的なレイヤーについて

Azure Web Apps + ASP.NET は、IIS ワーカープロセスの上に、ASP.NET の AppDomain が作成されて、アプリが動作する構成をとっている。

その為、まず IIS ワーカープロセスの生成が必要で、その上で、AppDomain (= ASP.NET アプリ) を生成して初めてアプリが動作する。 操作によっては、ワーカープロセスごと再生成されたり、ワーカープロセスは変わらずに中の AppDomain だけが再生成されたりするが、それによってアプリが応答可能になるまでの待機時間が異なる(もちろん、ワーカープロセスからの再生成の方が時間がかかる)。

なお、InProc のセッション情報は AppDomain 側に用意されているようなので、ワーカープロセスの再起動だろうが AppDomain の再起動だろうが、InProc のセッション情報はリセットされる。

Web Apps のアプリ設定として「常時接続」の項目があるが、この項目がオフの場合は、アプリが 20 分間アイドル状態になった際に自動的に当該ワーカープロセスが終了させられるので注意 (恐らく、Azure ポータルで「再起動」を実行したのと同じ状態)。 稼働中のワーカープロセスがない状態でリクエストが来た場合は、ワーカープロセスの生成がまず発生するので、アプリが有効になってレスポンスが返るまでに時間がかかる。

AppDomain の切り替えの場合、ブラウザからのリクエストがエラーとなるタイミングはないようだが、ワーカープロセスの切り替えの場合はエラーとなるタイミングがある様子。

各操作時の挙動について

1 インスタンス、常時接続オンの状態で操作した際の挙動を簡単にまとめると、以下。

操作 再起動対象 備考
Azure ポータルでの「再起動」 ワーカープロセス WP 終了時、利用不可になるタイミングあり
ファイル日付更新 (デプロイ含む) AppDomain AppDomain 並行起動により、利用不可になるタイミングなし
Azure ポータルでのアプリ設定変更 ワーカープロセス WP 並行起動により、利用不可になるタイミングなし
スロットのスワップ - レスポンス準備整い次第ドメインスワップが行われるため、スワップ先が利用不可になるタイミングなし

注: 「利用不可になるタイミングなし」は、リクエスト元に 503 などアプリ管轄外のエラーが返らない事を指しているが、新しいアプリがどれぐらいでレスポンス可能になるかはアプリ次第なので、注意。 例えば、ASP.NET でプリコンパイルを行っていない場合などは、ワーカープロセスの再起動と同時にコンパイル済みのイメージも全て削除されて次回ページアクセス時に再度コンパイルが発生するため、エラーは返されないがレスポンスが返るまで非常に時間がかかる可能性がある。

各操作時の詳細な挙動は以下。

Azure ポータルでの「停止」

稼働中のワーカープロセスが落とされて、落とされた後にリクエストがあった場合も起動は行われない。 稼働中のワーカープロセスで処理中のリクエストが存在する場合は、そのリクエストが終わった後、ワーカープロセスが落とされる。

停止中にリクエストがあった場合は 1 が返されるが、停止完了した後は 2 のページが表示される。

  1. 「HTTP Error 503. The service is unavailable.」 (恐らく IIS のエラーレスポンス)
  2. 「Error 403 - This web app is stopped.」 (恐らく Azure Web Apps の既定のエラーページ)

常時接続オンの場合 常時接続オンの場合も、処理は同じ様子。

Azure ポータルでの「開始」

ワーカープロセスが起動可能状態となる(この時点で起動されるわけではない)。

初回リクエストが来た時点で、ワーカープロセスが起動されて、アプリの準備が出来次第、レスポンスが返される。

常時接続オンの場合 常時接続オンの場合は、リクエストの有無に依らず、開始実行後自動的にワーカープロセスが起動する。 また、ワーカープロセスの起動後に AppDomain も作成され、リクエストに即時応答出来る状態になる。

Azure ポータルでの「再起動」

稼働中のワーカープロセスが落とされて、Azure ポータルでの「開始」実行時と同じ状態になる。 なお、稼働中のワーカープロセスで処理中のリクエストが存在する場合は、そのリクエストの処理が終わった後、ワーカープロセスが落とされる。 再起動実行後、処理中のリクエストの完了待ちでワーカープロセスが終了できない状態で新たなリクエストが来た場合、新しいリクエストも既存のワーカープロセスでそのまま処理される様子。

再起動実行時にリクエストがあった場合、タイミングによっては以下のエラーが返されることがある。

「HTTP Error 503. The service is unavailable.」 (恐らく IIS のエラーレスポンス)

常時接続オンの場合 Azure ポータルでの「開始」と同様の動きになる様子。

bin フォルダ配下のファイル変更や、Web.config の変更 (Kudu から直接)

変更の検出は恐らくファイル更新日付。

稼働中ワーカープロセスはそのままで、中の AppDomain が変更後のアプリ用に同一ワーカープロセス内に新規作成されて、新しいリクエストを処理する。 なお、古い AppDomain がリクエストを処理中だった場合、そのリクエストの処理が完了した後に、古い AppDomain はシャットダウンされる(はず)。 古い AppDomain が処理中リクエストの完了待ちの状態で新たなリクエストが来た場合、新しいリクエストは並行して作成された新しい AppDomain で即座に処理される (Application_Start() にログをしかけて測定)。 一時的に新旧 AppDomain が共存する形となっているはずだが、画面などから確認するすべはない。

なお、完全にアンドキュメンテッドな内容だが、AppDomain リサイクル発生時に処理しているリクエストが存在した場合、処理中の全リクエストが完了して古い AppDomain がシャットダウンした直後に、新しい AppDomain が作成される(新しいリクエストがなかったとしても)。 逆に AppDomain リサイクル発生時に処理しているリクエストがない場合、新しい AppDomain が作成されるタイミングは、新しいリクエストが来たタイミングとなる。

AppDomain の切り替えに留まるからか、ブラウザから見ると新しい設定の準備が整うまで数秒程度の待ち時間は発生するが、利用不能な時間は発生しない様子。 なお、InProc のセッション情報は AppDomain 単位で持っているため、AppDomain 切り替えのタイミングでセッション情報もクリアされる。

常時接続オンの場合 常時接続オンの場合も、処理は同じ様子。

複数インスタンスが起動している場合 ストレージは全インスタンスが同じ場所を見ているため、ファイル変更は全インスタンスが同様に影響を受ける。

Visual Studio からの発行 (デプロイ)

基本的に Web.config の変更と同様の動きの様子(デプロイも結局の所は、ファイルのコピーなので)。

試してはいないが、DevOps からのデプロイ時なども同じ状態になるのではないかと思われる

Azure ポータルでのアプリ設定の変更

基本的には、Azure ポータルでの「再起動」と同じフローに見える。

ただこちらの操作の場合、既存リクエスト処理の終了待ち状態で受けた新たなリクエストは、終了待ちのワーカープロセスではなく新たなワーカープロセス上で処理されるようで、ここが「再起動」時と異なる。

また、終了待ちのワーカープロセスが終了するまで新しいワーカープロセスも起動しないようなので、新たなリクエストは終了待ちのワーカープロセスが終了するまで、待機することになる様子。

以下の説明を見る限り、一時的に重複してワーカープロセスが起動しそうな感じだが、自分が確認した限りでは、これは常時接続オンの場合の挙動だった。

常時接続オンの場合 常時接続オンの場合は、稼働中ワーカープロセスのシャットダウンを待たずに新規ワーカープロセスを並行起動して新しいリクエストを処理するため、稼働中ワーカープロセスのシャットダウン待ちの状態は発生しない。

詳細な動作はアンドキュメンテッドだが、アプリ設定変更後のリクエストも、新規ワーカープロセスがリクエスト待ち受け可能な状態になるまでは旧ワーカープロセスで受け付けてレスポンスを返し、新規ワーカープロセスがリクエスト待ち受け可能になったタイミングで新しいリクエストは全て新規ワーカープロセスで処理し、入れ替わりに旧ワーカープロセスがシャットダウンされるように見受けられる。

スロットのスワップ

スワップの注意点として、ソーススロットとターゲットスロットで行われる処理が異なる点がある。 スワップの目的は単純に 2 つのスロットを入れ替える事ではなく、「ターゲットスロットの動作を極力維持したままで、ソーススロットのアプリと入れ替える」事になる。 最終結果としてはアプリがソースとターゲットで入れ替わる事に違いはないが、この目的達成のために、入れ替わるまでの過程がそれぞれのスロットで異なる。

まず、アプリを入れ替えるために、アプリ設定などのスワップ処理が必要となるが、これらの処理は、基本的に全て「ソーススロット」で行われる。 アプリ設定などが変更されるとワーカープロセスの再起動が発生するが、これが行われるのはソーススロットのみなので、ターゲットスロットのワーカープロセスには影響が出ない。

ソーススロットにターゲットスロットの設定が適用し終えて、ソーススロットのワーカープロセスの準備が完了するまでは、ターゲットスロットで通常通りリクエストが処理される。 ソーススロットでの準備が全て完了したら、FQDN の付け替えを行う。 この時点からターゲットスロットへのリクエストは、ソーススロットで準備していたワーカープロセスで受けることになるが、既に準備は完了している状態なので、ブラウザの待ち時間などは基本的に発生しない (はず。あっても数秒程度)。

この後、ソーススロットで再度、ソーススロット用アプリの設定適用等が行われる。 スワップ完了までは、大体数分ほどかかる。

上記動作を見てもらうと分かると思うが、スワップ中は、一時的にではあるが、ターゲットスロットのアプリ設定で、ソーススロットのアプリが動作するタイミングがある。 そのため、スワップ中にソーススロット(の FQDN)に対して何かしらリクエストを行っていると、本来ターゲットスロットの接続先であるストレージや DB に対して、ソーススロットの FQDN のリクエスト処理が行われる可能性がある。 そのため、スワップ中は少なくともソーススロットに対するリクエストは禁止する必要がある。

プランの変更

Azure ポータルでの「再起動」と同様、既存のワーカープロセスが落とされて、開始可能状態となるように見える。

html のキャッシュ抑制方法

まず一番基本の、html ファイルのヘッダーにメタ情報として指定する方法は、下記。Cache-Control については no-cache もあるけど、no-store の方がキャッシュされない感じ。

<head>
  <meta http-equiv="Pragma" content="no-cache">
  <meta http-equiv="Cache-Control" content="no-store">
  <meta http-equiv="Expires" content="0">
</head>

ただ、html のキャッシュ抑制対応するには html ヘッダーの meta タグだけでは不十分なようで、キャッシュが表示される場合がある。 その場合 http レスポンスヘッダーにも追加することで、回避出来るみたい (静的 html ファイルも含めて)。

ASP.NET の場合、Web.config に以下のように設定を追加する。

Web.config

<system.webServer>
  <httpProtocol>
    <customHeaders>
        <add name="Pragma" value="no-cache"/>
        <add name="Cache-Control" value="no-store"/>
        <add name="Expires" value="0"/>
    </customHeaders>
  </httpProtocol>
</system.webServer>