/*
* (C) Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* ohun@live.cn (夜色)
*/
package com.mpush.test.push;
import com.mpush.api.push.*;
import com.mpush.common.qps.FlowControl;
import com.mpush.common.qps.GlobalFlowControl;
import com.mpush.tools.log.Logs;
import org.junit.Test;
import java.time.LocalTime;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
/**
* Created by ohun on 2016/1/7.
*
* @author ohun@live.cn
*/
public class PushClientTestMain2 {
public static void main(String[] args) throws Exception {
new PushClientTestMain2().testPush();
}
@Test
public void testPush() throws Exception {
Logs.init();
PushSender sender = PushSender.create();
sender.start().join();
Thread.sleep(1000);
Statistics statistics = new Statistics();
FlowControl flowControl = new GlobalFlowControl(1000);// qps=1000
ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(4);
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
System.out.println("time=" + LocalTime.now()
+ ", flowControl=" + flowControl.report()
+ ", statistics=" + statistics
);
}, 1, 1, TimeUnit.SECONDS);
for (int k = 0; k < 1000; k++) {
for (int i = 0; i < 1; i++) {
while (service.getQueue().size() > 1000) Thread.sleep(1); // 防止内存溢出
PushMsg msg = PushMsg.build(MsgType.MESSAGE, "this a first push.");
msg.setMsgId("msgId_" + i);
PushContext context = PushContext.build(msg)
.setAckModel(AckModel.NO_ACK)
.setUserId("user-" + i)
.setBroadcast(false)
.setTimeout(60000)
.setCallback(new PushCallback() {
@Override
public void onResult(PushResult result) {
statistics.add(result.resultCode);
}
});
service.execute(new PushTask(sender, context, service, flowControl, statistics));
}
}
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(30000));
}
private static class PushTask implements Runnable {
PushSender sender;
FlowControl flowControl;
Statistics statistics;
ScheduledExecutorService executor;
PushContext context;
public PushTask(PushSender sender,
PushContext context,
ScheduledExecutorService executor,
FlowControl flowControl,
Statistics statistics) {
this.sender = sender;
this.context = context;
this.flowControl = flowControl;
this.executor = executor;
this.statistics = statistics;
}
@Override
public void run() {
if (flowControl.checkQps()) {
FutureTask<PushResult> future = sender.send(context);
} else {
executor.schedule(this, flowControl.getDelay(), TimeUnit.NANOSECONDS);
}
}
}
private static class Statistics {
final AtomicInteger successNum = new AtomicInteger();
final AtomicInteger failureNum = new AtomicInteger();
final AtomicInteger offlineNum = new AtomicInteger();
final AtomicInteger timeoutNum = new AtomicInteger();
AtomicInteger[] counters = new AtomicInteger[]{successNum, failureNum, offlineNum, timeoutNum};
private void add(int code) {
counters[code - 1].incrementAndGet();
}
@Override
public String toString() {
return "{" +
"successNum=" + successNum +
", offlineNum=" + offlineNum +
", timeoutNum=" + timeoutNum +
", failureNum=" + failureNum +
'}';
}
}
}