I could use some pseudo-code, or better, Python. I am trying to implement a rate-limiting queue for a Python IRC bot, and it partially works, but if someone triggers less messages than the limit (e.g., rate limit is 5 messages per 8 seconds, and the person triggers only 4), and the next trigger is over the 8 seconds (e.g., 16 seconds later), the bot sends the message, but the queue becomes full and the bot waits 8 seconds, even though it's not needed since the 8 second period has lapsed.
Here the simplest algorithm, if you want just to drop messages when they arrive too quickly (instead of queuing them, which makes sense because the queue might get arbitrarily large):
rate = 5.0; // unit: messages
per = 8.0; // unit: seconds
allowance = rate; // unit: messages
last_check = now(); // floating-point, e.g. usec accuracy. Unit: seconds
when (message_received):
current = now();
time_passed = current - last_check;
last_check = current;
allowance += time_passed * (rate / per);
if (allowance > rate):
allowance = rate; // throttle
if (allowance < 1.0):
discard_message();
else:
forward_message();
allowance -= 1.0;
There are no datastructures, timers etc. in this solution and it works cleanly :) To see this, 'allowance' grows at speed 5/8 units per seconds at most, i.e. at most five units per eight seconds. Every message that is forwarded deducts one unit, so you can't send more than five messages per every eight seconds.
Note that rate should be an integer, i.e. without non-zero decimal part, or the algorithm won't work correctly (actual rate will not be rate/per). E.g. rate=0.5; per=1.0; does not work because allowance will never grow to 1.0. But rate=1.0; per=2.0; works fine.
Use this decorator #RateLimited(ratepersec) before your function that enqueues.
Basically, this checks if 1/rate secs have passed since the last time and if not, waits the remainder of the time, otherwise it doesn't wait. This effectively limits you to rate/sec. The decorator can be applied to any function you want rate-limited.
In your case, if you want a maximum of 5 messages per 8 seconds, use #RateLimited(0.625) before your sendToQueue function.
import time
def RateLimited(maxPerSecond):
minInterval = 1.0 / float(maxPerSecond)
def decorate(func):
lastTimeCalled = [0.0]
def rateLimitedFunction(*args,**kargs):
elapsed = time.clock() - lastTimeCalled[0]
leftToWait = minInterval - elapsed
if leftToWait>0:
time.sleep(leftToWait)
ret = func(*args,**kargs)
lastTimeCalled[0] = time.clock()
return ret
return rateLimitedFunction
return decorate
#RateLimited(2) # 2 per second at most
def PrintNumber(num):
print num
if __name__ == "__main__":
print "This should print 1,2,3... at about 2 per second."
for i in range(1,100):
PrintNumber(i)
A Token Bucket is fairly simple to implement.
Start with a bucket with 5 tokens.
Every 5/8 seconds: If the bucket has less than 5 tokens, add one.
Each time you want to send a message: If the bucket has ≥1 token, take one token out and send the message. Otherwise, wait/drop the message/whatever.
(obviously, in actual code, you'd use an integer counter instead of real tokens and you can optimize out the every 5/8s step by storing timestamps)
Reading the question again, if the rate limit is fully reset each 8 seconds, then here is a modification:
Start with a timestamp, last_send, at a time long ago (e.g., at the epoch). Also, start with the same 5-token bucket.
Strike the every 5/8 seconds rule.
Each time you send a message: First, check if last_send ≥ 8 seconds ago. If so, fill the bucket (set it to 5 tokens). Second, if there are tokens in the bucket, send the message (otherwise, drop/wait/etc.). Third, set last_send to now.
That should work for that scenario.
I've actually written an IRC bot using a strategy like this (the first approach). Its in Perl, not Python, but here is some code to illustrate:
The first part here handles adding tokens to the bucket. You can see the optimization of adding tokens based on time (2nd to last line) and then the last line clamps bucket contents to the maximum (MESSAGE_BURST)
my $start_time = time;
...
# Bucket handling
my $bucket = $conn->{fujiko_limit_bucket};
my $lasttx = $conn->{fujiko_limit_lasttx};
$bucket += ($start_time-$lasttx)/MESSAGE_INTERVAL;
($bucket <= MESSAGE_BURST) or $bucket = MESSAGE_BURST;
$conn is a data structure which is passed around. This is inside a method that runs routinely (it calculates when the next time it'll have something to do, and sleeps either that long or until it gets network traffic). The next part of the method handles sending. It is rather complicated, because messages have priorities associated with them.
# Queue handling. Start with the ultimate queue.
my $queues = $conn->{fujiko_queues};
foreach my $entry (#{$queues->[PRIORITY_ULTIMATE]}) {
# Ultimate is special. We run ultimate no matter what. Even if
# it sends the bucket negative.
--$bucket;
$entry->{code}(#{$entry->{args}});
}
$queues->[PRIORITY_ULTIMATE] = [];
That's the first queue, which is run no matter what. Even if it gets our connection killed for flooding. Used for extremely important things, like responding to the server's PING. Next, the rest of the queues:
# Continue to the other queues, in order of priority.
QRUN: for (my $pri = PRIORITY_HIGH; $pri >= PRIORITY_JUNK; --$pri) {
my $queue = $queues->[$pri];
while (scalar(#$queue)) {
if ($bucket < 1) {
# continue later.
$need_more_time = 1;
last QRUN;
} else {
--$bucket;
my $entry = shift #$queue;
$entry->{code}(#{$entry->{args}});
}
}
}
Finally, the bucket status is saved back to the $conn data structure (actually a bit later in the method; it first calculates how soon it'll have more work)
# Save status.
$conn->{fujiko_limit_bucket} = $bucket;
$conn->{fujiko_limit_lasttx} = $start_time;
As you can see, the actual bucket handling code is very small — about four lines. The rest of the code is priority queue handling. The bot has priority queues so that e.g., someone chatting with it can't prevent it from doing its important kick/ban duties.
to block processing until the message can be sent, thus queuing up further messages, antti's beautiful solution may also be modified like this:
rate = 5.0; // unit: messages
per = 8.0; // unit: seconds
allowance = rate; // unit: messages
last_check = now(); // floating-point, e.g. usec accuracy. Unit: seconds
when (message_received):
current = now();
time_passed = current - last_check;
last_check = current;
allowance += time_passed * (rate / per);
if (allowance > rate):
allowance = rate; // throttle
if (allowance < 1.0):
time.sleep( (1-allowance) * (per/rate))
forward_message();
allowance = 0.0;
else:
forward_message();
allowance -= 1.0;
it just waits until enough allowance is there to send the message. to not start with two times the rate, allowance may also initialized with 0.
One solution is to attach a timestamp to each queue item and to discard the item after 8 seconds have passed. You can perform this check each time the queue is added to.
This only works if you limit the queue size to 5 and discard any additions whilst the queue is full.
Keep the time that the last five lines were sent. Hold the queued messages until the time the fifth-most-recent message (if it exists) is a least 8 seconds in the past (with last_five as an array of times):
now = time.time()
if len(last_five) == 0 or (now - last_five[-1]) >= 8.0:
last_five.insert(0, now)
send_message(msg)
if len(last_five) > 5:
last_five.pop()
If someone still interested, I use this simple callable class in conjunction with a timed LRU key value storage to limit request rate per IP. Uses a deque, but can rewritten to be used with a list instead.
from collections import deque
import time
class RateLimiter:
def __init__(self, maxRate=5, timeUnit=1):
self.timeUnit = timeUnit
self.deque = deque(maxlen=maxRate)
def __call__(self):
if self.deque.maxlen == len(self.deque):
cTime = time.time()
if cTime - self.deque[0] > self.timeUnit:
self.deque.append(cTime)
return False
else:
return True
self.deque.append(time.time())
return False
r = RateLimiter()
for i in range(0,100):
time.sleep(0.1)
print(i, "block" if r() else "pass")
Just a python implementation of a code from accepted answer.
import time
class Object(object):
pass
def get_throttler(rate, per):
scope = Object()
scope.allowance = rate
scope.last_check = time.time()
def throttler(fn):
current = time.time()
time_passed = current - scope.last_check;
scope.last_check = current;
scope.allowance = scope.allowance + time_passed * (rate / per)
if (scope.allowance > rate):
scope.allowance = rate
if (scope.allowance < 1):
pass
else:
fn()
scope.allowance = scope.allowance - 1
return throttler
How about this:
long check_time = System.currentTimeMillis();
int msgs_sent_count = 0;
private boolean isRateLimited(int msgs_per_sec) {
if (System.currentTimeMillis() - check_time > 1000) {
check_time = System.currentTimeMillis();
msgs_sent_count = 0;
}
if (msgs_sent_count > (msgs_per_sec - 1)) {
return true;
} else {
msgs_sent_count++;
}
return false;
}
I needed a variation in Scala. Here it is:
case class Limiter[-A, +B](callsPerSecond: (Double, Double), f: A ⇒ B) extends (A ⇒ B) {
import Thread.sleep
private def now = System.currentTimeMillis / 1000.0
private val (calls, sec) = callsPerSecond
private var allowance = 1.0
private var last = now
def apply(a: A): B = {
synchronized {
val t = now
val delta_t = t - last
last = t
allowance += delta_t * (calls / sec)
if (allowance > calls)
allowance = calls
if (allowance < 1d) {
sleep(((1 - allowance) * (sec / calls) * 1000d).toLong)
}
allowance -= 1
}
f(a)
}
}
Here is how it can be used:
val f = Limiter((5d, 8d), {
_: Unit ⇒
println(System.currentTimeMillis)
})
while(true){f(())}
yet another solution
from collections import deque
from datetime import timedelta
from time import sleep
class RateLimiter:
def __init__(self, items: int, per: timedelta = timedelta(seconds=1)):
self.items = items
self.per = per
self.deque = deque(maxlen=items)
def count(self):
now = datetime.now()
self.deque.append(now)
def time_to_wait(self) -> timedelta:
if len(self.deque) < self.deque.maxlen:
return timedelta(0)
now = datetime.now()
per = now - self.deque[0]
return max(timedelta(0), self.per - per)
def throttle(self):
sleep(self.time_to_wait().total_seconds())
self.count()
if __name__ == '__main__':
rate_limiter = RateLimiter(items=3, per=timedelta(seconds=3))
for i in range(10):
rate_limiter.throttle()
print(f'{i}')
Related
I am trying to create a Countup counter Starting from 1 to 10000 and i do not want it to reset when user refreshes the page or cancels the page. The Counter should start from 1 for every user that visits the page and keep running in background till it gets to 10000 even if the page is closed.
I have written the page below which;
Starts from the specified number for every new visitor
Saves the progress and does not reset when page is refreshed, however
It does not keep counting when page is closed and starts from the last progress when user closes the tab and comes back later. My code is
function countUp() {
var countEl = document.querySelector('.counter');
var countBar = document.querySelector('.progress-bar');
var x = parseInt(localStorage.getItem('lastCount')) - 1 || 1;
var y = countEl.dataset.to;
var z = countBar.dataset.to;
function addNum() {
countEl.innerHTML = x;
x += 1;
if (x > y && x > z) {
clearInterval(timer);
}
localStorage.setItem('lastCount', x);
}
var timer = window.setInterval(addNum, 1000);
localStorage.setItem("addNum", counter);
toggleBtn.addEventListener('click', function(){
countUp();
toggleBtn.classList.add('hidden');
});
}
countUp();</script>
<body onload=countUp();>
<div class="counter" data-from="0" data-to="10000000"></div>
<div class="progress-bar" data-from="0" data-to="10000000"></div>
</body>
It's difficult to show an example on StackOverflow because it doesn't let you fiddle with localStorage but, it sounds like you want something like:
When a user visits the page check localStorage for a timestamp.
If timestamp exists, go to step 4
Timestamp doesn't exist so get the current timestamp and stash it in localStorage.
Get the current timestamp. Subtract the timestamp from before. If over 10,000, stop, you're done.
Display difference calculated in step 4.
Start a 1 second timer, when time is up, go to step 4.
Something along those lines should work even if they refresh the page and since you are calculating from the original timestamp it will "count" in the background even if the page is closed.
window.addEventListener("DOMContentLoaded", () => {
const start = localStorage.getItem("timestamp") || Date.now();
localStorage.setItem("timestamp", start);
function tick() {
const now = Date.now();
const seconds = Math.floor((now - start) / 1000);
const display = document.getElementById("display");
if (seconds > 10000) return display.innerHTML = "We're done";
display.innerHTML = seconds;
setTimeout(tick, 1000);
}
tick();
});
<div id="display"></div>
So, client-side code can't normally execute when a client-side javascript page is closed.
What you could do, however, is calculate where the timer should be then next time it is loaded.
For example, in your addNum() function, you could in addition to the last count, also store the current date (and time).
function addNum() {
countEl.innerHTML = x;
x += 1;
if (x > y && x > z) {
clearInterval(timer);
}
localStorage.setItem('lastCount', x);
localStorage.setItem('lastDate', new Date());
}
Then, when your code starts, you can retrieve lastDate, and then subtract the current Date() from it.
Then use that to add the difference to your counter.
function countUp() {
let storedCount = parseInt(localStorage.getItem('lastCount'));
let storedDate = Date.parse(localStorage.getItem('lastDate'));
let now = new Date()
let diffSeconds = (now.getTime() - storedDate.getTime()) / 1000;
let storedCount += diffSeconds;
var countEl = document.querySelector('.counter');
var countBar = document.querySelector('.progress-bar');
var x = storedCount - 1 || 1;
var y = countEl.dataset.to;
var z = countBar.dataset.to;
}
I'm sure there are some more changes required to make it work with your code, but the idea is to store the current time so that when the page is closed and reopened, you can 'adjust' the count to catch up to what it should be.
What you want here is not possible just from the client-side code, there is no way for 2 different machines to share that information at all.
Here's the thing though, you can do this with a backend where the database gets updated every time a new IP hits the server. Note with this approach, a user here is one system and not different browsers or sessions.
To update this real-time for someone who is already on the website, run a timer and call an API that specifically gives you the count. Therefore the page gets updated frequently. You can also do this with react-query as it comes with inbuilt functions to do all this.
The process.cpuUsage() function displays some weird microsecond values.
How to get cpu usage in percentage?
You can achieve this using the additional os native module to get informations about your CPUs:
const os = require('os');
// Take the first CPU, considering every CPUs have the same specs
// and every NodeJS process only uses one at a time.
const cpus = os.cpus();
const cpu = cpus[0];
// Accumulate every CPU times values
const total = Object.values(cpu.times).reduce(
(acc, tv) => acc + tv, 0
);
// Normalize the one returned by process.cpuUsage()
// (microseconds VS miliseconds)
const usage = process.cpuUsage();
const currentCPUUsage = (usage.user + usage.system) * 1000;
// Find out the percentage used for this specific CPU
const perc = currentCPUUsage / total * 100;
console.log(`CPU Usage (%): ${perc}`);
If you want to get the global CPU usage (taking all your CPUs into account), you need to accumulate every times of every CPUs, not only the first one, but that should be less useful in most cases.
Note that only the "system" time can use more than the first CPU because the calls can run in other threads separated from the NodeJS core.
Sources :
https://nodejs.org/api/os.html#os_os_cpus
https://nodejs.org/api/process.html#process_process_cpuusage_previousvalue
An alternative, assuming you are running node under linux/macos O.S. is:
var exec = require("child_process").exec;
function getProcessPercent() {
// GET current node process id.
const pid = process.pid;
console.log(pid);
//linux command to get cpu percentage for the specific Process Id.
var cmd = `ps up "${pid}" | tail -n1 | tr -s ' ' | cut -f3 -d' '`;
setInterval(() => {
//executes the command and returns the percentage value
exec(cmd, function (err, percentValue) {
if (err) {
console.log("Command `ps` returned an error!");
} else {
console.log(`${percentValue* 1}%`);
}
});
}, 1000);
}
getProcessPercent();
If your O.S is windows, your command must be different. As i'm not running windows i can't tell to you the exact command, but you can start from here:
tasklist
get-process
WMIC
You can also check the platform with process.platform and do an if/else statment setting the right command for the specific OS.
Before answering we need to take care about a couple of facts:
Node.js does not uses only one CPU, but every async I/O operation may use additional CPUs
the times returned by process.cpuUsage are cumulative of all CPUs used by the Node.js process
so to calculate the CPU usage of Node.js considering all the CPUs of the host, we could use something similar to:
const ncpu = require("os").cpus().length;
let previousTime = new Date().getTime();
let previousUsage = process.cpuUsage();
let lastUsage;
setInterval(() => {
const currentUsage = process.cpuUsage(previousUsage);
previousUsage = process.cpuUsage();
// we can't do simply times / 10000 / ncpu because we can't trust
// setInterval is executed exactly every 1.000.000 microseconds
const currentTime = new Date().getTime();
// times from process.cpuUsage are in microseconds while delta time in milliseconds
// * 10 to have the value in percentage for only one cpu
// * ncpu to have the percentage for all cpus af the host
// this should match top's %CPU
const timeDelta = (currentTime - previousTime) * 10;
// this would take care of CPUs number of the host
// const timeDelta = (currentTime - previousTime) * 10 * ncpu;
const { user, system } = currentUsage;
lastUsage = { system: system / timeDelta, total: (system + user) / timeDelta, user: user / timeDelta };
previousTime = currentTime;
console.log(lastUsage);
}, 1000);
or we can read the value of lastUsage from where we need it rather printing it to the console.
Try using the below code to get cpu usage in %
var startTime = process.hrtime()
var startUsage = process.cpuUsage()
// spin the CPU for 500 milliseconds
var now = Date.now()
while (Date.now() - now < 500)
var elapTime = process.hrtime(startTime)
var elapUsage = process.cpuUsage(startUsage)
var elapTimeMS = secNSec2ms(elapTime)
var elapUserMS = secNSec2ms(elapUsage.user)
var elapSystMS = secNSec2ms(elapUsage.system)
var cpuPercent = Math.round(100 * (elapUserMS + elapSystMS) / elapTimeMS)
console.log('elapsed time ms: ', elapTimeMS)
console.log('elapsed user ms: ', elapUserMS)
console.log('elapsed system ms:', elapSystMS)
console.log('cpu percent: ', cpuPercent)
function secNSec2ms (secNSec) {
return secNSec[0] * 1000 + secNSec[1] / 1000000
}
try tweaking the secNSec2ms function to the following to check if it solves your problem.
function secNSec2ms(secNSec) {
if (Array.isArray(secNSec))
return secNSec[0] * 1000 + secNSec[1] / 1000000 return secNSec / 1000;
}
I want to calculate the RSI - (Relative Strength Index)(Last 14 Days) for the Bitcoin-Price. The necessary data for the past 14 days comes from an API. The result should be stored in a variable for further processing. I tried different methods, but the result wasn´t working. I think i don´t found the right way to solve this. I was not able to create a complete and working result, so I am here to ask my first question on Stack Overflow.
How can I ask the API for the course of the past 14 days via
iterative timestamp manipulation?
Timestamp now -1day/-2days.... (&ts=xxxxxxxxxxxx) - example: (ts=1452680400)
https://min-api.cryptocompare.com/data/pricehistorical?fsym=BTC&tsyms=USD&ts=1452680400
How can i put the values from the API in an array?:
var closePrices= {
var : 'text',
array: [BTCDay1, BTCDay2, BTCDay3, BTCDay4, BTCDay5, BTCDay6, BTCDay7, BTCDay8, BTCDay9, BTCDay10, BTCDay11, BTCDay12, BTCDay13, BTCDay14]
};
Then I want to put the array in this calculation formular:
public static double CalculateRsi(IEnumerable<double> closePrices)
{
var prices = closePrices as double[] ?? closePrices.ToArray();
double sumGain = 0;
double sumLoss = 0;
for (int i = 1; i < prices.Length; i++)
{
var difference = prices[i] - prices[i - 1];
if (difference >= 0)
{
sumGain += difference;
}
else
{
sumLoss -= difference;
}
}
if (sumGain == 0) return 0;
if (Math.Abs(sumLoss) < Tolerance) return 100;
var relativeStrength = sumGain / sumLoss;
return 100.0 - (100.0 / (1 + relativeStrength));
}
Several quite broad questions (it usually works better if you post some of the code you already tried to write yourself)... But fun ones to solve.
Assuming we can use es6 syntax, Promises and fetch (if you can't, look up how to polyfill & transpile).
Creating an array of timestamps
To get a timestamp for the current date, you write Date.now(). To change this time stamp to a day n days ago, we decrease it by the number of milliseconds in a day:
const timeStampForDaysAgo =
nrOfDays => Date.now() - 1000 * 60 * 60 * 24 * nrOfDays;
// e.g.: yesterday
const yesterday = timeStampForDaysAgo(1);
Now, if we fill an array of the integers 0...14, we can use map to create an array of timestamps!
const lastTwoWeeks = Array.from(Array(14), (_, i) => timeStampForDaysAgo(i))
Doing the requests
In modern browsers, you can use fetch to do requests. We'll need a list of URLs though, not just timestamps. To make the URLs, we again use map:
const urls = lastTwoWeeks.map(ts => `https://your-url.com?ts=${ts}`);
Now that we have URLs, we can create our requests (again, using map):
const btcRequests = urls.map(url => fetch(url).then(r => r.json()));
Calculating the result
We can't start calculating the result until all requests have finished. That's where Promise.all comes in:
Promise.all(btcRequests).then(calcRSI);
This makes sure we only call calcRSI until all requests have finished.
Because the API returns objects of { BTC: { USD: Number } }, we'll have to extract the numbers before we can do our math.
Promise
.all(btcRequests)
.then(responses => responses.map(obj => obj.BTC.USD))
Now that we have an array of numbers, we can finally call the calculate function you gave in C# code. Of course, you'll have to translate it to javascript first.
const calcRSI = (arrayOfValues) => /* do math, return value */
Promise
.all(btcRequests)
.then(responses => responses.map(obj => obj.BTC.USD))
.then(calcRSI)
.then(rsi => console.log("The RSI for the last 14 days, is:", rsi);
See the code in action in this fiddle (make sure to open the console)
Does anybody know how to add multiple polls in a Facebook live post, as shown in this example by Super Deluxe: https://www.facebook.com/superdeluxevideo/videos/416419238702632/.
My idea was to create a button to store the current reactions count as an object in a (Firebase) database and subtract that from the reactions count given from the API to start from 0 on every new round. The problem with this is that when people react on the first poll and give a different reaction on the next, it subtracts the first reaction and puts that reaction into the negative.
For example: If the user pressed WOW on the first poll, the count is WOW:1 LOVE:0. When the poll is reset, those umbers are subtracted from what is being taken from the Facebook Graph API. So, if on the next poll, this user presses LOVE, the count switches to WOW:-1 LOVE:1.
Here's a basic example of the code I have, using Firebase to store the reaction values.
// Firebase config
firebase.initializeApp(config);
var database = firebase.database();
var dbCounter = database.ref('/counter');
var access_token = 'ACCESS_TOKEN', // PASTE HERE YOUR FACEBOOK ACCESS TOKEN
pageID = 'PAGE_ID', //Paste your Facebook Page ID here
postID = 'POST_ID', // PASTE HERE YOUR POST ID
postID = pageID+'_'+postID,
refreshTime = 5, // Refresh time in seconds
counter = {
love : 0,
wow : 0
},
cachedCounter = counter;
var reactions = ['LOVE', 'WOW'].map(function (e) {
var code = 'reactions_' + e.toLowerCase();
return 'reactions.type(' + e + ').limit(0).summary(total_count).as(' + code + ')'
}).join(',');
var refreshCounts = function() {
var url = 'https://graph.facebook.com/v2.8/' + postID + '?fields=' + reactions + '&access_token=' + access_token;
$.getJSON(url, function(res){
counter.love = res.reactions_love.summary.total_count;
counter.wow = res.reactions_wow.summary.total_count;
$('.reaction.love .count').text(counter.love);
$('.reaction.wow .count').text(counter.wow);
});
}
$(document).ready(function(){
// Update the value of cachedCounter every time the database is updated
dbCounter.on('value', function(res){
// res.val() starts with the same value as the default counter
cachedCounter = res.val();
});
// Only runs once
dbCounter.once('value').then(function(res){
setInterval(refreshCounts, refreshTime * 1000);
refreshCounts();
});
// Reset counters while keeping count of reactions for new poll
$('button.reset-count').click( function() {
// Save current counter in database
dbCounter.set(counter);
// Set counters to 0
$('.reaction .count').text(0);
return false;
} );
});
Would anybody happen to know how Super Deluxe is resetting the reaction count values in their implementation?
I ran into this same issue. It essentially came down to this:
If you run multiple polls in one video, you can't keep just on two reactions (e.g. Like/love) for the entire thing.
Let's use this scenario:
Poll 1 starts: 0 likes, 0 loves (nobody has voted yet)
Poll 1 ends: 100 likes, 200 loves. Loves win 66% / 33%.
Then, a few minutes later, we run Poll #2. If we reset the default back down to zero, that means we set an offset of whatever likes and loves are on the video when the new poll starts. So, we remove those from the votes.
Poll 2 starts: (from last vote) 100 likes, 200 loves. Offset set at -100, -200, so effectively 0 likes and 0 loves.
Now, when Poll 2 ends, that's when it gets difficult. Let's look at the scenario where we have a mix of people who have already voted and ones that are new.
5 people switch their vote from love to like.
5 people are new and decide to like it.
Love gets no additional votes.
Poll 2 ends: 10 likes (110 total likes - 100 offset from last vote), -5 loves (195 total loves - 200 offset from last vote).
We don't want that negative number.
My solution was to:
Switch from like/love to another reaction set (like haha/wow) every other vote
Reset the count (like the above offset) at the beginning of each voting period
This way, if people are voting, they're switching back and forth and effectively "resetting" the vote each time.
I'm using NodeJs.
I received constantly request from server.
I'm added some variable like createdTime to it and saved to the database.
when I sorted data by createdTime in some case It is not reliable, It is Repeated
How can I make differentiate between them ?
I do not want to count request.
I do not like to change timestamp's format.
var createdTime = new Date().getTime();
Here's a method of combining a counter with the current time to allow you to have as many as 1000 separate transactions within the same ms that are all uniquely numbered, but still a time-based value.
And, here's a working snippet to illustrate:
// this guarantees a unique time-based id
// as long as you don't have more than 1000
// requests in the same ms
var getTransactionID = (function() {
var lastTime, counter = 0;
return function() {
var now = Date.now();
if (now !== lastTime) {
lastTime = now;
counter = 0;
} else {
++counter;
}
return (now * 1000) + counter;
}
})();
for (var i = 0; i < 100; i++) {
document.write(getTransactionID() + "<br>");
}
If you want something that is likely to work across clusters, you can use process.hrtime() to use the high resolution timer instead of the counter and then make the id be a string that could be parsed into a relative time if needed. Since this requires node.js, I can't make a working snippet here in the browser, but here's the idea:
// this makes a unique time-based id
function getTransactionID () {
var now = Date.now();
var hrtime = process.hrtime();
return now + "." + ((hrtime[0] * 1e9) + hrtime[1]);
}
Due to my low rep I can't add a comment but it looks like you are needing to go beyond milliseconds.Maybe this stackoverflow question can help you
How to get a microtime in Node.js?