
毎年12月24日の夜には、「子どもたちのもとにサンタクロースが訪れてプレゼントを贈る」といわれています。「サンタクロースが世界中の子どもにプレゼントを配るにはどうすればいいのか」の量子論的解釈を、科学系ニュースサイトのPhys.orgが紹介しています。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
しかし、サンタクロースが実在したとして、世界中の子どもに一晩でプレゼントを配るのは至難の業。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
ドイツ・ドルトムント大学の物理学研究者であるメティン・トラン氏は自著「Silent Night, Hasty Night.(きよしこの夜、はやい夜)」の中で、「サンタクロースが、仮に『その1年でいい子だった10歳までのキリスト教徒の子どもたち』だけを対象にプレゼントを配達したとしても、24時間で2億3400万世帯を訪問する必要がある」と論じています。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
24時間で2億3400万世帯ということは、サンタクロースは1秒あたり約2700件の家を訪問しなければならないことを意味します。仮に地球の自転に逆らって移動したとしても、制限時間は合計32時間で、配達ノルマは1秒あたり約2000件。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
これは人間が見ることができる最大フレームレートをはるかに越えているため、「だからこそ我々は、サンタクロースが働いている姿を観察することができない」とトラン氏は述べています。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
トラン氏は「サンタクロースは空間全体に存在し、すべての状態を記述する波動状態に置き換えられる必要があります」と述べています。つまり、サンタクロースは1人ではなく、サンタクロースのすべての状態を重ね合わせた「サンタクロース波」を考えるというのがトラン氏のアイデアです。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
ただし、サンタクロースが目撃されれば、その時点でサンタクロースが確定してしまい、サンタクロースの波動状態は崩壊してしまいます。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
トラン氏は「このサンタクロース波がある限り、宇宙の終わりまでサンタクロースが生き延びることを示します。サンタクロースは20×1048年という永遠の時間をずっと旅をしているのです」と述べています。
サンタクロースを量子論的に解釈する、世界中に爆速でプレゼントを配るサンタが燃え尽きて消滅しないためには? - GIGAZINE
⇧ 何と言うか、「空想科学読本」を彷彿とさせますな...
まぁ、「サンタクロース波」の状態で活動できるとは思えませんが...
最早、「ホラー(Horror)」の領域という感じになって来ており、狂気が入り混じってるとしか思えないのよ...
Oxidizedの環境変数CONFIG_RELOAD_INTERVAL有効時のリロードで処理の不整合が起こる時があるかも
例の如く、「Ruby」製の「ライブラリ」である「oxidized」のバグであろうと思われる事象についての原因の推測を備忘録として。
公式の「ドキュメント」によりますと、
⇧ 上記にありますように、「CONFIG_RELOAD_INTERVAL」という「環境変数」を利用すると、「oxidized」の「設定」ファイルを再読み込みしてくれるとありますと。
なのだが、「oxidized」では「Ruby」の「Thread」を利用しているらしく、且つ、「リロード」の処理が「node」の「状態」の更新処理を考慮できていないため、タイミングによって正常に動作しないことがありますと。
残念ながら、「oxidized」の「設計」が破綻していることによる「バグ」っぽいので、おそらく、改修はされない気がする...
仕組みとしては、
■https://github.com/ytti/oxidized/blob/master/extra/auto-reload-config.runit
#!/bin/bash
if [ -z "$CONFIG_RELOAD_INTERVAL" ]; then
# Just stop and do nothing
sleep infinity
fi
while true; do
sleep $CONFIG_RELOAD_INTERVAL
echo "Reloading config..."
curl -s http://localhost:8888/reload?format=json -O /dev/null
done
⇧ 上記にあるように、無限ループしている中で、「CONFIG_RELOAD_INTERVAL」に指定した「秒数」のタイミングで、「oxidized-web」の「エンドポイント」に対してリクエストを実施している。
で、「oxidized-web」の該当の処理はというと、
■https://github.com/ytti/oxidized-web/blob/master/lib/oxidized/web/webapp.rb
...省略
get '/reload.?:format?' do
node = params[:node]
node ? (nodes.load node) : nodes.load
@data = node ? "reloaded #{node}" : 'reloaded list of nodes'
out
end
…省略
def out(template = :text)
if @json || (params[:format] == 'json')
if @data.is_a?(String)
json @data.lines
else
json @data
end
elsif (template == :text) || (params[:format] == 'text')
content_type :text
@data
else
haml template, layout: true
end
end
…省略
def nodes
settings.nodes
end
…省略
⇧ とあり、「oxidized-web」側で「nodes」の起点はというと、
■https://github.com/ytti/oxidized-web/blob/master/lib/oxidized/web.rb
...省略
def initialize(nodes, configuration)
require 'oxidized/web/webapp'
@configuration = self.class.parse_configuration(configuration)
WebApp.set :nodes, nodes
WebApp.set :configuration, @configuration
WebApp.set :host_authorization, {
permitted_hosts: @configuration[:vhosts]
}
uri_prefix = @configuration[:uri_prefix]
@app = Rack::Builder.new do
map uri_prefix do
run WebApp
end
end
end
...省略
⇧ 上記の「Web」クラスのインスタンス化の際に、引数として受け取った「nodes」になるのだが、「Web」クラスのインスタンス化は、「oxidized」側で実施されているらしく、
■https://github.com/ytti/oxidized/blob/master/lib/oxidized/core.rb
...省略
def initialize(_args)
Oxidized.mgr = Manager.new
Oxidized.hooks = HookManager.from_config(Oxidized.config)
nodes = Nodes.new
raise NoNodesFound, 'source returns no usable nodes' if nodes.empty?
@worker = Worker.new nodes
@need_reload = false
# If we receive a SIGHUP, queue a reload of the state
reload_proc = proc do
@need_reload = true
end
Signals.register_signal('HUP', reload_proc)
# Load extensions, currently only oxidized-web
# We have different namespaces for oxidized-web, which needs to be
# adressed if we need a generic way to load extensions:
# - gem: oxidized-web
# - module: Oxidized::API
# - path: oxidized/web
# - entrypoint: Oxidized::API::Web.new(nodes, configuration)
# Initialize oxidized-web if requested
if Oxidized.config.has_key? 'rest'
logger.warn(
'configuration: "rest" is deprecated. Migrate to ' \
'"extensions.oxidized-web" and remove "rest" from the configuration'
)
configuration = Oxidized.config.rest
elsif Oxidized.config.extensions &&
Oxidized.config.extensions['oxidized-web']&.load?
# This comment stops rubocop complaining about Style/IfUnlessModifier
configuration = Oxidized.config.extensions['oxidized-web']
end
if configuration
begin
require 'oxidized/web'
rescue LoadError
raise OxidizedError,
'oxidized-web not found: install it or disable it by ' \
'removing "rest" and "extensions.oxidized-web" from your ' \
'configuration'
end
@rest = API::Web.new nodes, configuration
@rest.run
end
run
end
...省略
⇧ 上記の処理で、
- oxidized
- oxidized-web
の両方から、更新されてしまう状況になってしまいますと...
しかも、お互い「非同期」での処理になるので、変なタイミングで更新処理が実施された場合、表題の件のような処理の不整合が発生することになると思われる。
ちなみに、「node」の処理は「Thread」として管理される模様。
module Oxidized
class Job < Thread
include SemanticLogger::Loggable
attr_reader :start, :end, :status, :time, :node, :config
def initialize(node)
@node = node
@start = Time.now.utc
self.name = "Job '#{@node.name}'"
super do
logger.debug "Starting fetching process for #{@node.name}"
begin
Timeout.timeout(Oxidized.config.timelimit) do
@status, @config = @node.run
end
logger.debug "Config fetched for #{@node.name}"
rescue Timeout::Error
logger.warn "Job timelimit reached for #{@node.name}"
@status = :timelimit
ensure
@end = Time.now.utc
@time = @end - @start
end
end
end
end
end
そして、「node」の「状態」は「Worker」クラスで管理されるのだが、
■https://github.com/ytti/oxidized/blob/master/lib/oxidized/worker.rb
...省略
def work
ended = []
@jobs.delete_if { |job| ended << job unless job.alive? }
ended.each { |job| process job }
@jobs.work
while @jobs.size < @jobs.want
logger.debug "Jobs running: #{@jobs.size} of #{@jobs.want} - ended: " \
"#{@jobs_done} of #{@nodes.size}"
# ask for next node in queue non destructive way
nextnode = @nodes.first
unless nextnode.last.nil?
# Set unobtainable value for 'last' if interval checking is disabled
last = Oxidized.config.interval.zero? ? Time.now.utc + 10 : nextnode.last.end
break if last + Oxidized.config.interval > Time.now.utc
end
# shift nodes and get the next node
node = @nodes.get
node.running? ? next : node.running = true
@jobs.push Job.new node
logger.debug "Added #{node.group}/#{node.name} to the job queue"
end
if cycle_finished?
run_done_hook
exit 0 if Oxidized.config.run_once
end
logger.debug("#{@jobs.size} jobs running in parallel") unless @jobs.empty?
end
def process(job)
node = job.node
node.last = job
node.stats.add job
@jobs.duration job.time
node.running = false
if job.status == :success
process_success node, job
else
process_failure node, job
end
rescue NodeNotFound
logger.warn "#{node.group}/#{node.name} not found, removed while collecting?"
end
...省略
⇧ 上記の「node」の「状態」の「更新」のタイミングと「リロード」処理のタイミングがバッティングすると、「last」の判定が意図したものではなくなり、処理の整合性が崩れることになると思われますと。
ただでさえ、厄介な「ミュータブル(Mutable)」な構造になってしまっているにもかかわらず、「状態」の「更新」に影響し得るのが、
- oxidized
- oxidized-web
の2か所になり、「処理」の「排他制御」もされていないので、意図せぬ「更新」が発生し得るリスクを抱えていると...
とりあえず、
- oxidized
- oxidized-web
の「設計」の「思想」が分からないので推測するしか無いのだが、何となくだが、「メッセージキューイング(MQ:Message Queueing)」的な「機能」を導入したかったのかは謎だが、おそらく、「処理」を「疎結合」にしたかったのかもしれないが、見事に「設計」が破綻してはいそうなのよね...
まぁ、「Oxidized」の他に代替できそうな「ライブラリ」が無いので、芳しくない「設計」の「ライブラリ」と理解した上で利用せざるを得ないのだが、せめて、公式の「ドキュメント」に「情報」を載せて欲しい気はする...
今日も今日とて、ストレスが蓄積されていきますな...
毎度モヤモヤ感が半端ない…
今回はこのへんで。
