rozek avatar
rozek
floatingQuotaTracker
Script
Public vals often use resources which have some usage limits ("quota"). Publishing such vals carries the risk that these quotas may be exceeded. For this reason, it makes sense to keep track of resource consumption and trigger a relevant response when a preset limit is reached (for example, one could provide the user with a meaningful error message). The "floatingQuotaTracker" is designed to help monitor resources that may only be used a certain number of times in a given (but floating) time span (e.g., 10 times a minute). Simply add an invocation of the "floatingQuotaTracker" into your val just before the tracked resource is going to be used and, from then on, that resource will be tracked and protected against excessive consumption. Usage Example Using a floatingQuotaTracker (within the val that requires the resource) is quite simple: import { floatingQuotaTracker } from 'https://esm.town/v/rozek/floatingQuotaTracker' const ResourceTable = 'xxx' // enter name of sqlite table that can be used const ResourceLimit = 10 // max. number of allowed requests per period const ResourcePeriod = 60*1000 // the period, given in ms const Granularity = 5*1000 // how precisely should be logged? ;(async () => { const Tracker = await floatingQuotaTracker.new( ResourceTable, ResourceLimit,ResourcePeriod, Granularity ) let exceeded = await Tracker.LimitExceeded() // true if quota exceeded // can be used to chech the current status let TimeToWait = await Tracker.TimeToWait() // how long to wait before... // ...the resource may be used again? await Tracker.incrementIfAllowed() // increments resource usage if allowed // or throws a "LimitExceeded" exception otherwise ... now use your resource as usual })() Simply provide the following settings: ResourceTable - the name prefix of an sqlite table ResourceLimit - how many calls are allowed within the given ResourcePeriod ResourcePeriod - the time span relevant for usage counting Granularity - how precisely should be logged? large values produce less rows in the sqlite tables and are therefore more efficient, but may let you wait longer The "floatingQuotaTracker" is designed to be accessed simultaneously from multiple vals without interfering with each other. API Reference static async new (Name:string, Limit:number = 10, Period:number = 60*1000, Granularity:number = 5*1000):Promise<floatingQuotaTracker> creates a new tracker instance. Name is a prefix for SQLite tables (which must match the RegEx pattern /^[a-z_][0-9a-z_]+$/i ), Limit is the maximum calls per period, Period is the time window in ms, and Granularity is the time resolution in ms ( Limit , Period and Granularity are optional and only needed when the tracking tables are created) async Limit(): Promise<number> returns the current usage limit async setLimit (newLimit:number):Promise<void> sets a new usage limit. newLimit must be a cardinal number async Period ():Promise<number> returns the current time period in milliseconds async setPeriod (newPeriod:number):Promise<void> sets a new time period. newPeriod must be a cardinal number representing milliseconds async Granularity ():Promise<number> returns the current time granularity in milliseconds async setGranularity (newGranularity:number):Promise<void> sets a new time granularity. newGranularity must be a cardinal number representing milliseconds async reset ():Promise<void> clears all usage data async Usage ():Promise<number> returns the total usage within the current period async LimitExceeded ():Promise<boolean> checks if the usage limit has been exceeded async increment ():Promise<void> increases the usage count for the current time slot async incrementIfAllowed ():Promise<void> increases the usage count if the limit hasn't been exceeded. Throws a 'LimitExceeded' error otherwise async TimeToWait ():Promise<number> returns the time in milliseconds to wait before the next allowed increment, or 0 if increment is currently allowed Tests Some tests can be found in val floatingQuotaTracker_Test
0
rozek avatar
rozek
InvocationTracker
Script
If you make a val public, you may probably also want to see how often that val is used - perhaps even including some statistics which show how often that val was called in a given time span. This is exactly what the "InvocationTracker" was written for. Simply include a call to the "InvocationTracker" in your val, and from then on any invocations will be tracked in an sqlite table allowing you to easily calculate how often the val was used in total or get the time course of calls. Usage Example Using an InvocationTracker (within the val that should be monitored) is quite simple: import { InvocationTracker } from 'https://esm.town/v/rozek/InvocationTracker' const TrackingTable = 'xxx' // enter name of sqlite table that can be used const Granularity = 15*60*1000 // how precisely should be logged? ;(async () => { const Tracker = await InvocationTracker.new(TrackingTable,Granularity) await Tracker.increment() // logs this invocation ... now continue as usual })() Later, you may then use the "InvocationTracker" to provide you with some statistics: import { InvocationTracker } from 'https://esm.town/v/rozek/InvocationTracker' const TrackingTable = 'xxx' // enter name of sqlite table that can be used ;(async () => { const Tracker = await InvocationTracker.new(TrackingTable,Granularity) /**** define the time span that interests you ****/ const from = new Date('xxx').getTime() // enter start date of your time span const to = Date.now() // here we are interested in all invocations until now /**** get the total number of invocations in the given time span ****/ const totalInvocations = await Tracker.totalInvocationsInSpan(from,to) /**** get more information about when your val was called over time ****/ const Invocations = await Tracker.InvocationsInSpan(from,to) // format: [{ Time,Invocations },...] with the given granularity // only times with actual invocations are listed, idle times are skipped })() The "InvocationTracker" is designed to be accessed simultaneously from multiple concurrently running vals without interfering with each other. API Reference static async new (Name:string, Granularity:number = 15*60*1000):Promise<InvocationTracker> creates a new "InvocationTracker" instance. Name must match /^[a-z_][0-9a-z_]+$/i , Granularity is the time resolution in milliseconds async Granularity ():Promise<number> returns the current time resolution in milliseconds async setGranularity (newGranularity:number):Promise<void> sets a new time resolution (in milliseconds). newGranularity must be an integer >= 1 async reset ():Promise<void> clears all recorded invocations async increment ():Promise<void> increments the invocation count for the current time period async InvocationsInSpan (from:number, to:number):Promise<{ Time:number, Invocations:number }[]> returns a list of invocation counts within the specified time span. from and to are Unix timestamps in milliseconds async totalInvocationsInSpan (from:number, to:number):Promise<number> returns the total number of invocations within the specified time span. from and to are Unix timestamps in milliseconds Tests Some tests can be found in val InvocationTracker_Test
0
1
Next
rozek-openrouterchatcompletion.web.val.run
Updated: February 1, 2025