Giter VIP home page Giter VIP logo

lua-resty-timer-ng's Introduction

lua-resty-timer-ng

A scalable timer library for OpenResty.

Status

This library is currently considered experimental.

Synopsis

http {
    init_worker_by_lua_block {
        local timer_module = require("resty.timerng")

        local options = {}
        local timer_sys = timer_module.new(options)

        local function callback_once(premature, ...)
            ngx.log(ngx.ERR, "in timer at")
        end

        local function callback_every(premature, ...)
            ngx.log(ngx.ERR, "in timer every")
        end

        -- run after 100 ms
        local name, err = timer_sys:at(0.1, callback_once)

        if not name then
            ngx.log(ngx.ERR, err)
        end

        -- run every 1s
        name , err = timer_sys:every(1, callback_every)

        if not name then
            ngx.log(ngx.ERR, err)
        end
    }
}

Description

This system is based on the timer wheel algorithm. which uses the small number of timers created by OpenResty API ngx.timer.at to manage a large number of timed tasks.

In other words, it can reduce the number of fake requests.

  • Efficiently, create, pause, start and cancel a timer takes O(1) time.
  • Concurrency control, you can limit the number of threads.
  • Easy to debug
    • Get statistics such as maximum, minimum, average, and variance of the runtime for each timer.
    • Some information that is useful for debugging, such as where the timer was created and the call stack at that time.

Statistics

The system records the following information:

  • The maximum, minimum, average, and variance of the running time of each timer.
  • The location of each timer created, such as call stack.

Debug Mode

The following information will be recorded in debug mode.

  • The callstack when the timer was created
  • The elapsed_time for each timer
  • The timers that are running
  • Timers that are queued

In debug mode, you can call stats() to get the raw data needed to generate the flamegraph.

Maximum delay/interval

-- for resolution, please see `timer_module.new(options?)`
max_delay = resolution
max_interval = resolution

-- for wheel_setting, please see `timer_module.new(options?)`
for _, slots in ipairs(wheel_setting.slots_for_each_level) do
    max_delay = max_delay * slots
    max_interval = max_interval * slots
end

max_delay = max_delay - 2       -- second
max_interval = max_interval - 2 -- second

Exceeding this range will use OpenResty's timer.

History

Versioning is strictly based on Semantic Versioning

Methods

new

syntax: timer, err = require("resty.timerng").new(options?)

context: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

For example

local timer_module = require("resty.timerng")
local timer_sys = timer_module.new({
    -- debug mode
    debug = false,

    -- 100ms
    resolution = 0.1,

    restart_thread_after_runs = 5000,

    -- automatically adjusts the number of threads according to the load
    -- load = (running_timers + pending_timers) / threads
    auto_scaling_load_threshold = 5,

    min_threads = 32,
    max_threads = 256,

    -- 0.1 is resolution
    -- max_delay/interval = 10 * 60 * 60 * 21 * 0.1 second
    wheel_setting = {
        level = 4,
        slots_for_each_level = { 10, 60, 60, 24 } ,
    }
})

start

syntax: ok, err = timer:start()

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Start the timer system.

freeze

syntax: timer:freeze()

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Suspend the timer system and the expiration of each timer will be frozen.

named_at

syntax: name_or_false, err = timer:named_at(name, delay, callback, ...)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Create a once timer. You must call this method after you have called timer:start(). If you have called timer:pause(), you must call this function after you have called timer:start().

  • name: The name of this timer, or if it is set to nil, a random name will be generated.
  • callback: A callback function will be called when this timer expired, function callback(premature, ...).
  • delay: The expiration of this timer.

named_every

syntax: name_or_false, err = timer:named_every(name, interval, callback, ...)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Create a recurrent timer. You must call this method after you have called timer:start(). If you have called timer:pause(), you must call this function after you have called timer:start().

  • name: The name of this timer, or if it is set to nil, a random name will be generated.
  • callback: A callback function will be called when this timer expired, function callback(premature, ...).
  • interval: The expiration of this timer.

at

Equivalent to timer:named_at(nil, delay, callback, ...)

every

Equivalent to timer:named_every(nil, interval, callback, ...)

resume

syntax: ok, err = timer:resume(name)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Start a timer that has been paused and resets its expiration.

  • name: The name of this timer.

pause

syntax: ok, err = timer:pause(name)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Pause a timer that has been started.

  • name: The name of this timer.

cancel

syntax: ok, err = timer:cancel(name)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Cancel a timer.

  • name: The name of this timer.

destroy

syntax: timer:destroy()

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Destroy all timers and the object is no longer available.

Any operation (except GC) on this object after calling this method is undefined.

is_managed

syntax: timer:is_managed(name)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Return true if the specified timer is managed by this system, and false otherwise.

  • name: name of timer

set_debug

syntax: timer:set_debug(status)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Enable or disable debug mode.

  • status: If true then debug mode will be enabled and vice versa debug mode will be disabled.

stats

syntax: info, err = timer:stats(options?)

context: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*

Get the statistics of the system.

  • options:
    • verbose: If true, the statistics for each timer will be returned, defualt false.
    • flamegraph: If true and verbose == true, the raw data of flamegraph will be returned, you can run flamegraph.pl <output> > a.svg to generate flamegraph, default false.

For example:

local info, err = timer:stats(true)

if not info then
    -- error
end

-- info.sys = {
--     running = [number],      number of running timers
--     pending = [number],      number of pending timers
--     waiting = [number],      number of unexpired timers
--     total   = [number],      running + pending + waiting
-- }
local sys_info = info.sys


local flamegraph = info.flamegraph

-- flamegraph.running | pending | elapsed_time (second * 1000)
-- is a string, which is fold stacks, like
-- @/lualib/background.lua:32:init();@/lualib/background.lua:64:start_dns_timer() 16
-- @/lualib/background.lua:46:init();@/lualib/background.lua:128:start_cache_timer() 76
-- you can run `flamegraph.pl <output> > a.svg` to generate flamegraph.
-- ref https://github.com/brendangregg/FlameGraph


for timer_name, timer in pairs(info.jobs) 
    local is_running = timer.is_running
    local meta = timer.meta
    local stats = timer.stats
    local runs = timer.runs                     -- total number of runs

    -- meta.name is an automatically generated string 
    -- that stores the location where the creation timer was created.
    -- Such as 'task.lua:56:start_background_task()'

    -- meta.callstack is a string.


    stats = {
        -- elapsed_time is a table that stores the 
        -- maximum, minimum, average and variance 
        -- of the time spent on each run of the timer (second).
        elapsed_time = {
            max = 100
            min = 50
            avg = 70
            variance = 12
        },

        -- total number of runs
        runs = 0,

        -- Number of successful runs
        finish = 0,

        last_err_msg = "",
    }
end

License

Copyright 2016-2022 Kong Inc.

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.

lua-resty-timer-ng's People

Contributors

add-sp avatar gruceo avatar chronolaw avatar dndx avatar rodman10 avatar saisatishkarra avatar

Stargazers

 avatar ffffff0 avatar Nontawat Numor avatar zhanglei avatar  avatar

Watchers

Isa Farnik avatar Guanlan D. avatar John Fitzpatrick avatar Xiaochen Wang avatar Marco Palladino avatar Aapo Talvensaari avatar Wanny Morellato avatar  avatar Zhongwei Yao avatar Ryan Moore avatar Keery Nie avatar Christian Johannsen avatar Michael Martin avatar  avatar Brent Yarger avatar Yufu Zhao avatar  avatar Shiroko avatar Felderi Santiago avatar  avatar  avatar  avatar

Forkers

zhanglei rodman10

lua-resty-timer-ng's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.