現在、Android 向けに作成しているゲームのライブ テストを行っています。サービスは Rails 3.1 で書かれており、私は Postgresql を使用しています。私のより技術に精通したテスターの何人かは、リクエストをサーバーに記録し、高い並行性でそれらを再生することで、ゲームを操作することができました。コードにとらわれることなく、以下のシナリオを簡単に説明しようと思います。
- ユーザーは複数のアイテムを購入でき、各アイテムはデータベースに独自のレコードを持っています。
- 要求はコントローラー アクションに送られ、トランザクションに関する情報を記録する購入モデルが作成されます。
- トレード モデルには、アイテムの購入を設定するメソッドがあります。基本的に、いくつかの論理的な手順を実行して、アイテムを購入できるかどうかを確認します。最も重要なのは、いつでもユーザーごとに 100 アイテムの制限があることです。すべての条件が満たされると、要求された数のアイテムを作成するために単純なループが使用されます。
つまり、彼らが行っているのは、プロキシ経由で 1 つの有効なリクエストの購入を記録することです。次に、高い並行性でそれを再生します。これにより、本質的に、毎回いくつかの余分なものがすり抜けることができます。つまり、100 個購入するように設定した場合、300 ~ 400 個まで取得できます。また、15 個購入する場合は、120 個程度まで取得できます。
上記の購入方法はトランザクションでラップされます。ただし、ラップされていても、リクエストがほぼ同時に実行されている特定の状況では停止しません。これにはDBロックが必要になるかもしれないと推測しています。知っておく必要があるもう 1 つのひねりは、任意の時点で rake タスクがユーザー テーブルに対して cron ジョブで実行され、プレイヤーのヘルスとエネルギー属性を更新することです。したがって、それもブロックできません。
どんな支援も本当に素晴らしいでしょう。これは私のちょっとした趣味のサイド プロジェクトであり、ゲームが公正で誰にとっても楽しいものであることを確認したいと考えています。
本当にありがとう!
コントローラーのアクション:
def hire
worker_asset_type_id = (params[:worker_asset_type_id])
quantity = (params[:quantity])
trade = Trade.new()
trade_response = trade.buy_worker_asset(current_user, worker_asset_type_id, quantity)
user = User.find(current_user.id, select: 'money')
respond_to do |format|
format.json {
render json: {
trade: trade,
user: user,
messages: {
messages: [trade_response.to_s]
}
}
}
end
end
取引モデル方法:
def buy_worker_asset(user, worker_asset_type_id, quantity)
ActiveRecord::Base.transaction do
if worker_asset_type_id.nil?
raise ArgumentError.new("You did not specify the type of worker asset.")
end
if quantity.nil?
raise ArgumentError.new("You did not specify the amount of worker assets you want to buy.")
end
if quantity <= 0
raise ArgumentError.new("Please enter a quantity above 0.")
end
quantity = quantity.to_i
worker_asset_type = WorkerAssetType.where(id: worker_asset_type_id).first
if worker_asset_type.nil?
raise ArgumentError.new("There is no worker asset of that type.")
end
trade_cost = worker_asset_type.min_cost * quantity
if (user.money < trade_cost)
raise ArgumentError.new("You don't have enough money to make that purchase.")
end
# Get the users first geo asset, this will eventually have to be dynamic
potential_total = WorkerAsset.where(user_id: user.id).length + quantity
# Catch all for most people
if potential_total > 100
raise ArgumentError.new("You cannot have more than 100 dealers at the current time.")
end
quantity.times do
new_worker_asset = WorkerAsset.new()
new_worker_asset.worker_asset_type_id = worker_asset_type_id
new_worker_asset.geo_asset_id = user.geo_assets.first.id
new_worker_asset.user_id = user.id
new_worker_asset.clocked_in = DateTime.now
new_worker_asset.save!
end
self.buyer_id = user.id
self.money = trade_cost
self.worker_asset_type_id = worker_asset_type_id
self.trade_type_id = TradeType.where(name: "market").first.id
self.quantity = quantity
# save trade
self.save!
# is this safe?
user.money = user.money - trade_cost
user.save!
end
end