So...
I'm creating a plugin.
I have a main Class called Basics
Globally in Basics I create:
static Timer enterdungeon = new Timer();
static Timer finddungeon = new Timer();
static Timer lootdungeon = new Timer();
Also I have a class named task
the enterdungeon timer is a fixed period of time, and seems to work as expected when used.
As is the same for thee lootdungeon timer.
The finddungeon timer can be interrupted IF an event in basics is triggered.
The event DOES trigger fine
the top line in this event is:
finddungeon.cancel();
after it starts the lootdungeon timer.
the problem is the finddungeon timer does not cancel, it continues to run, below is the task class:
import java.util.TimerTask;
import me.boduzapho.Basics.DoWarp.Returner;
import org.bukkit.entity.Player;
public class task extends TimerTask
{
private final Player _player;
private final int ticks;
private int cnt = 0;
private final int _sec;
private final String _message;
public task(Player player, int sec, String message)
{
this._player = player;
this._sec = sec;
this._message = message;
this.ticks = sec;
}
private void timetoloot(Player p)
{
p.sendMessage("SUCCESS! Nice Job, Enjoy the loot!");
Returner loc1 = DoWarp.getwarp("launch", Basics.warps, Basics.wx,Basics.wy, Basics.wz, p);
DoWarp.warpme(loc1.x, loc1.y, loc1.z, p, false, Basics.plugin);
}
private void failedwhiteblock(Player p)
{
p.sendMessage("FAIL! You did not find the white block. Sending you back. TRY AGAIN!");
Returner loc1 = DoWarp.getwarp("launch", Basics.warps, Basics.wx, Basics.wy, Basics.wz, p);
DoWarp.warpme(loc1.x, loc1.y, loc1.z, p, false, Basics.plugin);
}
private void enterdungeon(Player p)
{
Basics.Stage.setLine(3, "Off you Go!");
Basics.Stage.update();
Basics.Stage.setLine(0, "");
Basics.Stage.setLine(1, "");
Basics.Stage.setLine(2, "");
Basics.Stage.setLine(3, "");
Basics.Stage.update();
Basics.cDoClear(p);
Basics.cDoSpawners(p);
Basics.cDoRed(p);
Returner loc1 = DoWarp.getwarp("dstart", Basics.warps, Basics.wx, Basics.wy, Basics.wz, p);
DoWarp.warpme(loc1.x, loc1.y, loc1.z, p, false, Basics.plugin);
Basics.DungeonPlayer = p;
p.sendMessage("Welcome to the Dungeon, you have 1 minuite to locate and click the white block.");
p.sendMessage("If you fail you will be returned to spawn. If you find it the treasures will be revieled");
p.sendMessage("and the monsters banished for 1 min so you can loot the chests! After which you will");
p.sendMessage("Be warped back to spawn with your Loot!");
Basics.finddungeon.schedule(new task(_player, 30, "Time left to find the WHITE block :"), 0, 1000);
Basics.enterdungeon.cancel();
}
#Override
public void run()
{
while (cnt < ticks)
{
try
{
Thread.sleep(1 * 1000);
_player.sendMessage(_message + " " + Integer.toString(_sec - cnt));
++cnt;
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
_player.sendMessage("Done!");
if (_message == "Time left:")
{
enterdungeon(_player);
}
if (_message == "Time left to find the WHITE block :")
{
failedwhiteblock(_player);
}
if (_message == "Time left to LOOT:")
{
timetoloot(_player);
}
//
return;
}
}
Here is the function called in Basics (main class) that is supposed to cancel the finddungeon timer.
// white block in dungeon
if (DungeonPlayer == player)
{
if ((block != null) && (block.getType() == Material.WOOL))
{
player.sendMessage("Canceling finddungeon from Basics");
finddungeon.cancel();
cDoClear(player);
cDoChests(player);
player.sendMessage("Congradulations! Time to Loot your rewards for finding the White Block!");
Timer lootdungeon = new Timer();
lootdungeon.schedule(new task(player, 10, "Time left to LOOT:"), 0, 1000);
return;
// ***
}
}
Can anyone shed any light on this?
Cause TimerTask.cancel doesn't do anything to the active task, it just clears the scheduler. You'll have to override cancel method, or just use this as a starting point:
class MyTimerTask extends TimerTask {
private volatile Thread thread;
#Override
public void run() {
thread = Thread.currentThread();
//do your task and keep your eye on InterruptedException when doing Sleeps, Waits
//also check Thread.interrupted()
}
public boolean cancel() {
Thread thread = this.thread;
if (thread != null) {
thread.interrupt();
}
return super.cancel();
}
}
Related
I'm new to Polly and I'm trying to apply the Retry policy, so that I can have it manually handling the retry connection in case of IBMMQ connection issue.
Please, consider the following code:
public class ReconnectException : Exception
{
}
public class QueueMonitor : IObservable<Message>, IDisposable
{
private readonly MQQueue mqQueue;
private readonly MQQueueManager queueManager;
private readonly string queueName;
private IDisposable timer;
private readonly object lockObj = new object();
private bool isChecking;
private readonly TimeSpan checkingFrequency;
private readonly List<IObserver<Message>> observers;
private TimeSpan reconnectInterval;
private readonly IScheduler scheduler;
private readonly int maxReconnectCount;
private static readonly ILog Logger = LogProvider.For<AonQueueManager>();
private readonly Policy pollyPolicy;
public QueueMonitor(IConfiguration configuration, string queueName, IScheduler scheduler = null)
{
this.queueManager = QueueFactory.GetIstance(configuration);
this.queueName = queueName;
this.scheduler = scheduler ?? Scheduler.Default;
checkingFrequency = configuration.GetValue("checkingFrequency", new TimeSpan(0, 0, 5));
reconnectInterval = configuration.GetValue("reconnectInterval", new TimeSpan(0, 0, 5));
maxReconnectCount = configuration.GetValue("maxReconnectCount", 3);
observers = new List<IObserver<Message>>();
pollyPolicy = Policy.Handle<ReconnectException>().WaitAndRetry(maxReconnectCount, _ => TimeSpan.FromSeconds(2));
mqQueue = queueManager.AccessQueue(queueName,
MQC.MQOO_INPUT_AS_Q_DEF // open queue for input
+ MQC.MQOO_FAIL_IF_QUIESCING); // but not if MQM stopping
}
public void Start()
{
var x = pollyPolicy.ExecuteAndCapture(CreateTimer);
}
private void CreateTimer()
{
Logger.DebugFormat("Repeating timer started, checking frequency: {checkingFrequency}", checkingFrequency);
timer = Observable.Interval(checkingFrequency, scheduler).Subscribe(_ =>
{
lock (lockObj)
{
if (isChecking) return;
Logger.Log(LogLevel.Debug, () => "Listening on queues for new messages");
isChecking = true;
var mqMsg = new MQMessage();
var mqGetMsgOpts = new MQGetMessageOptions { WaitInterval = checkingFrequency.Milliseconds };
// 15 second limit for waiting
mqGetMsgOpts.Options |= MQC.MQGMO_WAIT | MQC.MQGMO_FAIL_IF_QUIESCING |
MQC.MQCNO_RECONNECT_Q_MGR | MQC.MQOO_INPUT_AS_Q_DEF;
try
{
mqQueue.Get(mqMsg, mqGetMsgOpts);
if (mqMsg.Format.CompareTo(MQC.MQFMT_STRING) == 0)
{
var text = mqMsg.ReadString(mqMsg.MessageLength);
Logger.Debug($"Message received : [{text}]");
Message message = new Message { Content = text };
foreach (var observer in observers)
observer.OnNext(message);
}
else
{
Logger.Warn("Non-text message");
}
}
catch (MQException ex)
{
if (ex.Message == MQC.MQRC_NO_MSG_AVAILABLE.ToString())
{
Logger.Trace("No messages available");
//nothing to do, emtpy queue
}
else if (ex.Message == MQC.MQRC_CONNECTION_BROKEN.ToString())
{
Logger.ErrorException("MQ Exception, trying to recconect", ex);
throw new ReconnectException();
}
}
finally
{
isChecking = false;
}
}
});
}
public IDisposable Subscribe(IObserver<Message> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
public void Dispose()
{
((IDisposable)mqQueue)?.Dispose();
((IDisposable)queueManager)?.Dispose();
timer?.Dispose();
}
}
public class Unsubscriber : IDisposable
{
private readonly List<IObserver<Message>> observers;
private readonly IObserver<Message> observer;
public Unsubscriber(List<IObserver<Message>> observers, IObserver<Message> observer)
{
this.observers = observers;
this.observer = observer;
}
public void Dispose()
{
if (observer != null) observers.Remove(observer);
}
}
The problem I've is that when an exception is thrown inside the lamda ( throw new ReconnectException();), Polly doesn't catch it (and I understand why, since it's on another thread) and the application quits since it's on a different thread.
This code is a part of a library,so I don't know that if in every project the Global exceptions are correctly handed.
How do I get it "catched" by the Polly's code?
Thanks in advance
The code posted in the question applies the policy only to the act of creating the timer (the execution of CreateTimer()), not to the code executed by the timer (the lambda inside the .(Subscribe(_ => { }) call).
This is the same as the behaviour if the call to CreateTimer() was surrounded by a try { } catch { }. The catch would only cover the act of executing the CreateTimer() method, the creation of the timer.
For the Polly policy to govern exceptions thrown within the lambda, it needs to be applied within the lambda, to the relevant block/group of statements which are expected to throw the exception.
For example, you might code:
pollyPolicy.ExecuteAndCapture(() => mqQueue.Get(mqMsg, mqGetMsgOpts));
(with a policy configured to govern the particular MQException/s you want to handle).
Or you can apply the policy to a wider group of statements - just as with a try { } clause.
pollyPolicy.ExecuteAndCapture(() =>
{
// ...
mqQueue.Get(mqMsg, mqGetMsgOpts));
// ...
}
I'm doing batching of messages in stream want to do it by 3 conditions:
if batcher can't add incoming message (for whatever internal logic of batcher)
if there were messages and then no messages within X seconds (basically what throttle does)
if there is continious stream of messages more often then every X seconds, then after Y seconds still close batch (cap on throttle)
I need to be able to change X and Y seconds in runtime without losing current batch (doesn't matter if it is closed immediately on config change or by closing conditions).
Condition function and batch process function should not run in parallel threads.
I'm using Rx-Main 2.2.5.
So far I came up with solution below and it seems to work, but I think there may be much simpler solution with reactive extensions?
Also with this solution capTimer doesn't restart if closing condition is "batcher can't add this message".
Extension:
public static class ObservableExtensions
{
public static IDisposable ConditionalCappedThrottle<T>(this IObservable<T> observable,
int throttleInSeconds,
int capTimeInSeconds,
Func<T, bool> conditionFunc,
Action capOrThrottleAction,
Action<T, Exception> onException,
T fakeInstance = default(T))
{
Subject<T> buffer = new Subject<T>();
var capTimerObservable = new Subject<long>();
var throttleTimerObservable = observable.Throttle(TimeSpan.FromSeconds(throttleInSeconds)).Select(c => 1L);
IDisposable maxBufferTimer = null;
var bufferTicks = observable
.Do(c =>
{
if (maxBufferTimer == null)
maxBufferTimer = Observable.Timer(TimeSpan.FromSeconds(capTimeInSeconds))
.Subscribe(x => capTimerObservable.OnNext(1));
})
.Buffer(() => Observable.Amb(
capTimerObservable
.Do(c => Console.WriteLine($"{DateTime.Now:mm:ss.fff} cap time tick closing buffer")),
throttleTimerObservable
.Do(c => Console.WriteLine($"{DateTime.Now:mm:ss.fff} throttle time tick closing buffer"))
))
.Do(c =>
{
maxBufferTimer?.Dispose();
maxBufferTimer = null;
})
.Where(changes => changes.Any())
.Subscribe(dataChanges =>
{
buffer.OnNext(fakeInstance);
});
var observableSubscriber = observable.Merge(buffer)
.Subscribe(subject =>
{
try
{
if (!subject.Equals(fakeInstance)) {
if (conditionFunc(subject))
return;
Console.WriteLine($"{DateTime.Now:mm:ss.fff} condition false closing buffer");
maxBufferTimer?.Dispose();
}
capOrThrottleAction();
if (!subject.Equals(fakeInstance))
conditionFunc(subject);
}
catch (Exception ex)
{
onException(subject, ex);
}
});
return new CompositeDisposable(maxBufferTimer, observableSubscriber);
}
}
And usage:
class Program
{
static void Main(string[] args)
{
messagesObs = new Subject<Message>();
new Thread(() =>
{
while (true)
{
Thread.Sleep(random.Next(3) * 1000);
(messagesObs as Subject<Message>).OnNext(new Message());
}
}).Start();
while (true)
{
throttleTime = random.Next(8) + 2;
maxThrottleTime = random.Next(10) + 20;
Console.WriteLine($"{DateTime.Now:mm:ss.fff} resubscribing with {throttleTime} - {maxThrottleTime}");
Subscribe();
Thread.Sleep((random.Next(10) + 60) * 1000);
}
}
static Random random = new Random();
static int throttleTime = 3;
static int maxThrottleTime = 10;
static IDisposable messagesSub;
static IObservable<Message> messagesObs;
static void Subscribe()
{
messagesSub?.Dispose();
BatchProcess();
messagesSub = messagesObs.ConditionalCappedThrottle(
throttleTime,
maxThrottleTime,
TryAddToBatch,
BatchProcess,
(msg, ex) => { },
new FakeMessage());
}
static bool TryAddToBatch(Message msg)
{
if (random.Next(100) > 85)
{
Console.WriteLine($"{DateTime.Now:mm:ss.fff} can't add to batch");
return false;
}
else
{
Console.WriteLine($"{DateTime.Now:mm:ss.fff} added to batch");
return true;
}
}
static void BatchProcess()
{
Console.WriteLine($"{DateTime.Now:mm:ss.fff} Processing");
Thread.Sleep(2000);
Console.WriteLine($"{DateTime.Now:mm:ss.fff} Done Processing");
}
}
public class Message { }
public class FakeMessage : Message { }
Tests I want to work:
public class Test
{
static Subject<Base> sub = new Subject<Base>();
static int maxTime = 19;
static int throttleTime = 6;
// Batcher.Process must be always waited before calling any next Batcher.Add
static void MaxTime()
{
// foreach on next Batcher.Add must be called
sub.OnNext(new A());
Thread.Sleep(6 * 1000 - 100);
sub.OnNext(new A());
Thread.Sleep(6 * 1000 - 100);
sub.OnNext(new A());
Thread.Sleep(6 * 1000 - 100);
// Process must be called after 19 seconds = maxTime
}
static void Throttle()
{
// foreach on next Batcher.Add must be called
sub.OnNext(new A());
Thread.Sleep(6 * 1000 - 100);
sub.OnNext(new A());
Thread.Sleep(6 * 1000 - 100);
// Process must be called after 5.9+5.9+6 seconds = throttleTime
}
static void Condition()
{
// foreach on next Batcher.Add must be called
sub.OnNext(new A());
Thread.Sleep(6 * 1000 - 100);
sub.OnNext(new B());
// Process must be called because Batcher.Add will return false
// Batcher.Add(B) must be called after Process
}
static void MaxTimeOrThorttleNotTickingRandomly()
{
sub.OnNext(new A());
// Process called by throttle condition in 6 seconds
Thread.Sleep(1000 * 100);
// Process is not called for remaining 94 seconds
sub.OnNext(new A());
// Process called by throttle condition in 6 seconds
}
static void Resub()
{
sub.OnNext(new A());
sub.OnNext(new A());
sub.OnNext(new A());
sub.OnNext(new A());
sub.OnNext(new A());
maxTime = 15;
throttleTime = 3;
// Process is called
// Resubs with new timinig conditions
sub.OnNext(new A());
// Process called by throttle condition in 3 seconds
}
}
public class Batcher
{
private Type batchingType;
public bool Add(Base element)
{
if (batchingType == null || element.GetType() == batchingType)
{
batchingType = element.GetType();
return true;
}
return false;
}
public void Process()
{
batchingType = null;
}
}
public class Base{}
public class A : Base { }
public class B : Base { }
I'm currently trying to diagnosis a bug where when a user is wanting to back out of the game activity using the back button it closes the window but doesn't seem to actually close the activity. The reason I think the activity isn't closing is because when a new game activity is started, the activity seems to call onFinish from CountDownTimer and close as if the time ran out when the timer in game shows there is still time left in the new game. Essentially I think my old activity is closing my new activity, even after the activity is no longer showing and should be closed based on my onBackPressed() method.
Here is my code:
public class Game extends Activity {
ImageButton position0;
ImageButton position1;
ImageButton position2;
ImageButton position3;
Button colorPosition;
RelativeLayout background;
Random rand = new Random();
int[] position = {0,1,2,3};
int score = 0;
int streak = 1;
int multi = 1;
int currentColor;
SharedPreferences gamePrefs;
boolean countDisable = true;
public static final String GAME_PREFS = "ColorMatchFile";
TextView scoreText;
TextView multiplierText;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
gamePrefs = getSharedPreferences(GAME_PREFS, 0);
scoreText = (TextView) findViewById(R.id.score);
multiplierText= (TextView) findViewById(R.id.multiplier);
background = (RelativeLayout) findViewById(R.id.background);
StartCount start_count = new StartCount(5000, 1000);
start_count.start();
colorPosition = (Button)findViewById(R.id.colorPosition);
position0 = (ImageButton)findViewById(R.id.position0);
position1 = (ImageButton)findViewById(R.id.position1);
position2 = (ImageButton)findViewById(R.id.position2);
position3 = (ImageButton)findViewById(R.id.position3);
if(savedInstanceState != null){
int exScore = savedInstanceState.getInt("score");
scoreText.setText("Score: "+ exScore);
}
#Override
public void onBackPressed() {
setHighScore();
finish();
Intent intent = new Intent(getApplicationContext(), score_screen.class);
startActivity(intent);
super.onBackPressed();
}
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture,long countDownInterval){
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
final TextView time = (TextView) findViewById(R.id.time);
time.setText("Times Up!");
Thread thread = new Thread();
try {
thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
setHighScore();
finish();
Intent intent = new Intent(getApplicationContext(), score_screen.class);
startActivity(intent);
}
#Override
public void onTick(long millisUntilFinished){
final TextView time = (TextView) findViewById(R.id.time);
time.setText("Left: " + millisUntilFinished/1000);
}
}
public class StartCount extends CountDownTimer{
public StartCount(long millisInFuture,long countDownInterval){
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
final TextView time = (TextView) findViewById(R.id.time);
time.setText("Begin!");
MyCount counter = new MyCount(30000, 1000);
currentColor = rand.nextInt(4);
setCurrentColor(currentColor);
countDisable = false;
counter.start();
}
#Override
public void onTick(long millisUntilFinished){
final TextView time = (TextView) findViewById(R.id.time);
time.setText("Start In: " + millisUntilFinished/1000);
showCurrentPosition();
}
}
Well the problem was I wasn't turning the counter for MyCount off. Here is how I solved it:
#Override
public void onBackPressed() {
setHighScore();
counter.cancel();
this.finish();
Intent intent = new Intent(getApplicationContext(), score_screen.class);
startActivity(intent);
}
Note I had to use counter.cancel() and make counter a global variable.
I'm trying to create a graph with displays the last n seconds of data arriving by bluetooth. I want to add to the series from within a timer by adding a DataPoint with a Date as X value. All I get is a white screen. I think that the problem lies with the values used in ´graph.getViewport().setMinX`.
What value should I set for minX and maxX if I want to display the last n seconds of data?
public class MainActivity extends ActionBarActivity {
private Handler mHandler;
private GraphView graph;
LineGraphSeries<DataPoint> serFl = new LineGraphSeries<DataPoint>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initGraph();
mHandler = new Handler();
startRepeatingTask();
}
private void initGraph() {
try {
graph = (GraphView) findViewById(R.id.graph);
serFl.setColor(Color.BLUE);
graph.addSeries(serFl);
graph.getViewport().setXAxisBoundsManual(true);
graph.getViewport().setMinX(System.currentTimeMillis() - 10000);
graph.getViewport().setMaxX(System.currentTimeMillis() + 1000);
graph.getViewport().setYAxisBoundsManual(true);
graph.getViewport().setMinY(0);
graph.getViewport().setMaxY(20);
final SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
graph.getGridLabelRenderer().setLabelFormatter(
new DefaultLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
Date d = new Date((long) value);
return sdf.format(d);
} else {
// show currency for y values
return super.formatLabel(value, isValueX);
}
}
});
} catch (Exception x) {
System.err.println(x);
}
}
Runnable mStatusChecker = new Runnable() {
#Override
public void run() {
updateStatus();
mHandler.postDelayed(mStatusChecker, mInterval);
}
};
void startRepeatingTask() {
mStatusChecker.run();
}
protected void updateStatus() {
DataMessage msg = source.fetch();
long d = msg.getTimestamp();
serFl.appendData(new DataPoint(d, msg.getFl()), true,
settings.getMaxSeriesSize());
}
void stopRepeatingTask() {
mHandler.removeCallbacks(mStatusChecker);
}
}
You did not
graph.onDataChanged(false, false);
after setting the graph.getViewport().setMaxY(20);.
This helped in my case.
I have done the below thread pool program but the problem is that the WaitCallBackMethod(here ThreadPoolCallback) is getting called 2 times(which ideally should be called 1ce). what is the misktake I am making?
public class Calculation
{
#region Private variable declaration
ManualResetEvent[] factorManualResetEvent = null;
#endregion
public void Compute()
{
factorManualResetEvent = new ManualResetEvent[2];
for (int i = 0; i < 2; i++){
factorManualResetEvent[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(ThreadPoolCallback, i);}
//Wait for all the threads to complete
WaitHandle.WaitAll(factorManualResetEvent);
//Proceed with the next task(s)
NEXT_TASK_TO_BE_EXECUTED();
}
#region Private Methods
// Wrapper method for use with thread pool.
public void ThreadPoolCallback(Object threadContext)
{
int threadIndex = (int)threadContext;
Method1();
Method2();
factorManualResetEvent[threadIndex].Set();
}
private void Method1 ()
{ //Code of method 1}
private void Method2 ()
{ //Code of method 2 }
#endregion
}
If I do
//Initializang all the manual reset events first
Enumerable.Range(0, exposureManualResetEvent.Length).ToList().ForEach(i =>
{
exposureManualResetEvent[i] = new ManualResetEvent(false);
});
Enumerable.Range(0, 1).ToList().ForEach(i =>
{
ThreadPool.QueueUserWorkItem(ExposureThreadPoolCallback, i);
});
The program gets hang!
I am using C#3.0
Thanks
Well, think of ThreadPoolCallback as the ThreadProc for each thread you execute (ThreadPool.QueueUserWorkItem() starts a new thread each time you call it.).
Since you are Queuing 2 threads, you're going to get two calls to the Proc.
You are calling it twice:
for (int i = 0; i < 2; i++)
{
factorManualResetEvent[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(ThreadPoolCallback, i);
}