package stormapplied.flashsale.topology;
import backtype.storm.task.TopologyContext;
import backtype.storm.task.OutputCollector;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import stormapplied.flashsale.metrics.MultiSuccessRateMetric;
import stormapplied.flashsale.services.FlashSaleClient;
import stormapplied.flashsale.domain.Sale;
import stormapplied.flashsale.services.Timeout;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
public class LookupSalesDetails extends BaseRichBolt {
private final static int TIMEOUT = 100;
private FlashSaleClient client;
private OutputCollector outputCollector;
private final int METRICS_WINDOW = 15;
private transient MultiSuccessRateMetric sucessRates;
@Override
public void prepare(Map config,
TopologyContext context,
OutputCollector outputCollector) {
this.outputCollector = outputCollector;
client = new FlashSaleClient(TIMEOUT);
sucessRates = new MultiSuccessRateMetric();
context.registerMetric("sales-lookup-success-rate", sucessRates, METRICS_WINDOW);
}
@Override
public void execute(Tuple tuple) {
String customerId = tuple.getStringByField("customer");
List<String> saleIds = (List<String>) tuple.getValueByField("sales");
List<Sale> sales = new ArrayList<Sale>();
for (String saleId: saleIds) {
try {
Sale sale = client.lookupSale(saleId);
sales.add(sale);
} catch (Timeout e) {
sucessRates.scope(customerId).incrFail(1);
outputCollector.reportError(e);
}
}
if (sales.isEmpty()) {
outputCollector.fail(tuple);
} else {
sucessRates.scope(customerId).incrSuccess(sales.size());
outputCollector.emit(new Values(customerId, sales));
outputCollector.ack(tuple);
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("customer", "sales"));
}
}