Commit graph

2142 commits

Author SHA1 Message Date
Ankush Menat
ba6e3f6cd1 test: igore edge case of invalid strings
We parse them as None instead of 1-1-1 etc
2025-01-15 12:07:06 +05:30
Ankush Menat
829062b1e3 fix: make shared jenv thread-safe
A new copy is created for each request, but cache is shared.
2025-01-15 11:53:00 +05:30
Ankush Menat
129212a916 perf: cache unseen notes 2025-01-14 19:43:22 +05:30
Ankush Menat
c72e91f465
fix: backward compatible date parsing (#29155)
Even though we never use tz aware object in frappe this function
previously used to retain them, so keep TZinfo for sake of compat.

Nothing should be affected ideally.
2025-01-14 11:05:55 +00:00
Ankush Menat
b6a0e849a0 fix: Avoid mixing client cache and redis_wrapper 2025-01-14 15:20:47 +05:30
Ankush Menat
b49d512404 feat: cache documents in client cache
No need to query 1 key at a time.
2025-01-14 14:33:10 +05:30
Ankush Menat
4d1ef02e25 feat: generator support for client cache
Similar to redis, for ergonomics
2025-01-14 13:55:28 +05:30
Ankush Menat
fab464effb feat: support shared keys in client cache 2025-01-14 13:52:29 +05:30
Ankush Menat
fdba41c682
perf: misc client cache improvements (#29070)
* perf: Reduce penalty for lack of redis connection

If redis isn't running than this client cache is slower than default
implementation because of the extra locking overhead.

* test: update perf redis counts

* perf: cache table columns in client-cache

* fix: race condition on cache-client_cache init

Rare but apparant in synthetic benchmarks.

Cache is set but client cache is still being initialized then request
will fail.

* perf: Don't run notifications when loading document

WHAT?

* fix: use cached doc to repopulate

* perf: reduce get_meta calls
2025-01-07 16:14:43 +05:30
Ankush Menat
33bd1bc09b fix: Flushall shouldn't attempt reading keys 2025-01-07 11:56:22 +05:30
Ankush Menat
b5e2569c0c feat: statistics for cache performance
These can be used for logging or debugging the behaviour of the cache.
2025-01-07 11:47:52 +05:30
Ankush Menat
b7ddd1df92 perf: cache hooks in client-side cache 2025-01-06 20:24:27 +05:30
Ankush Menat
dfc6dcb6b8 Revert "perf: Avoid checking server script map (#29057)"
This reverts commit 55a55e7f7b.
2025-01-06 19:43:53 +05:30
Ankush Menat
c14d416d19 docs: add usage / notes in code 2025-01-06 19:28:37 +05:30
Ankush Menat
15f5adc25a refactor: use namedtuple for readability 2025-01-06 19:28:33 +05:30
Ankush Menat
119af71ae3 refactor: variable names, force RESP2 2025-01-06 18:57:57 +05:30
Ankush Menat
53f085e0f4 test: ttl and maxsize 2025-01-06 18:57:57 +05:30
Ankush Menat
f332852415 fix: start tracking keys set by us immediately 2025-01-06 18:57:57 +05:30
Ankush Menat
4518b4562f test: add basic client cache tests 2025-01-06 18:57:57 +05:30
Ankush Menat
8f2f94b7e5 test: make redis query count util work with any redis instance 2025-01-06 18:57:57 +05:30
Ankush Menat
55a55e7f7b
perf: Avoid checking server script map (#29057)
If I have to hazard a guess, 99% API calls are not server scripts, then
why check it first and pay the costs?

This PR first checks if method is a real method in python code and if
it's not found then only attempts to fetch it from server script map.

I'll revert this if I can bring the costs in acceptable limits with
client-side caching.
2025-01-06 07:40:20 +00:00
Ankush Menat
47af97661a test: avoid flaky behaviour on test ordering
If a test clears local.response and another test depends on it being
fresh inited then tests can fail.

E.g. response.docs might not exist.
2025-01-04 11:54:37 +05:30
Ankush Menat
13304cd36d ci: balance test distribution manually
Currently one test runner takes significantly longer than another. This
is entirely due to test_commands.py which needs to create new site and
do backup/restore tests etc. All of which are far far slower than other
tests.
2025-01-04 10:55:53 +05:30
Ankush Menat
51b11208e4 test: add perf test to prevent adding more redis calls 2025-01-01 14:42:13 +05:30
Ankush Menat
bada7cab13
perf: No need to set expiry for rate limiter key everytime (#28956)
* perf: No need to set expiry for key everytime

* fix: Set expiry on first request and never again

This prevents problem of rate limiter keys growing constantly.
2024-12-30 07:31:47 +00:00
Ankush Menat
0f546c33b3
test: impose tax on __init__.py (#28940)
Call it a new year's resolution.

`frappe/__init__.py` has grown crazy big over time and left unattended it will continue to grow.

This new ~test~ tax will require reducing 3 line per day (so ~1000 in a year) from 1st Jan 2025 onwards. I am offering a headstart of 50 days in this PR by moving ~150 lines: #28869
2024-12-28 10:16:33 +05:30
Ankush Menat
766cb64d55
perf!: Cache site configs in memory for 60 seconds (#28869)
This is middle ground between caching it completely and requiring a
restart/signal to reload vs always reloading it.

I don't know any use cases that can break from this, nowhere in code
configs should be expected to reload instantly.

This change is only applied to requests for now
2024-12-27 16:21:14 +00:00
Ankush Menat
3ab2c2fbcf
perf: speedup rate limiter by ~1.2x (#28920)
* perf: reuse current time

now_datetime is site-tz-aware, we don't need it here.

* perf: dont need redis transactions

* perf: use `time.time()` instead of datetime

Using `datetime.timestamp()` is a round-about way to use `time.time()`
with extra cost of dealing with datetime and timezones.

* perf: define slots for rate_limiter

* fix!: Remove used rate limit header

This just shares how much was consumed in current request, people can
just time requests to get an approximation for this, not sure why is this
useful.
2024-12-26 10:57:46 +00:00
Akhil Narang
21a6d2a717
Merge pull request #28868 from akhilnarang/printview-cleanup-checks
chore(printview): change error message
2024-12-23 15:27:54 +05:30
Ankush Menat
fe63af5449
refactor: make optimizations.py private entirely (#28872)
Avoids having to prefix everything with `_`.
2024-12-23 09:56:56 +00:00
Akhil Narang
5a4239fbe3
chore(printview): change error message
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-12-23 13:29:44 +05:30
Ankush Menat
7d4d6b59df
test: reduce noise in test output (#28862)
* chore: remove verbose output from test runner

This is same output that's shared by test runner in different format?

This makes it annoying to scroll through when just running single test
locally.

* fix: Remove clutter from test output

Test records don't change after first run.
Tests are executed many many times locally

* test: retry flaky postgres backup tests
2024-12-23 06:11:47 +00:00
Ankush Menat
d466578348
perf(gthread): Pin web workers to a single core (#28854)
Python's multithreaded model is _inefficient_ because of Global
Interpreter Lock (GIL). Any one thread of process can run at any given
time. Thus only valid use case for threads in Python are:

1. Hiding I/O latency by switching to a different thread.
2. Using compiled extensions that yield GIL for long enough time to do
   meaningful work in other threads.

Both of these are not as frequent as you'd imagine and gthread worker
with multiple threads often just end up contending on lock and waste
useful CPU cycles doing nothing. Pinning worker process to a core nearly
eliminates this contention wastage. This waste can be 5-10% and goes up
sharply with more threads.

E.g. FC typically has maxed out config of 24 workers which allows
"accepting" and working on 24 requests at a time. But that doesn't mean
24 requests are on CPU at any given time, that would require 24 physical
cores.

Why do this?

1. Context switching in threads is faster than switching process - fewer
   cache misses, fewer TLB misses etc.
2. The model is simple
    True parallelism = count(cores) = count(processes).
    Expected concurrency = count(processes) * count(threads).
3. This is far simpler to reason about than something like async
   executor model.
4. Ability to queue more requests than what can be handled is already
   implemented by `bind(2)` and `accept(2)` in kernel. There is no real
   benefit of accepting 1000 requests if you can only work on 20 of them
   at a time. This is because we do a lot of "work" in requests, it's
   not just issuing an external request and waiting for it.
5. We can achieve practically same concurrency as 24 workers with 4
   process x 6 threads. That's a lot of memory saved to run other useful
   things.

Caveats:
- This kind of pinning can potentially make Linux scheduler inefficient.
  I don't quite think it's going to be a big problem because there are
  plenty of other things to run which a core can steal from other core
  if it doesn't have enough work.
- Load balancing in single-server multi-bench setup. I *think* by nature
  of how `accept(2)` works, load balancing will still happen pretty much
  automatically. If certain core is overloaded, naturally other cores
  will reach `accept(2)` more frequently and take the load off of that
  core. This is something worth validating in practice by creating
  skewed affinities.
- This code is not NUMA-aware. None of our machines have NUMA nodes so,
  I am ignoring it. Don't use it if you have a NUMA setup.
- If new CPUs are hotplugged or existing ones are disabled then it can
  be inefficient (worse than current) until that worker auto-restarts (which
  happens after N requests in FC setup).

Ideal solution: We write userspace scheduler to implement
"soft-affinity" using Linux's new eBPF based sched_ext feature. That's
too much extra work but I'll consider this too at some point.

closes https://github.com/frappe/caffeine/issues/13
2024-12-22 16:59:13 +05:30
Ankush Menat
1c2f8abb4e
perf: speedup get_datetime by ~9.5x (#28840) 2024-12-19 20:01:45 +05:30
Ankush Menat
3297aff294 fix: Always set value in local even if it expires 2024-12-17 18:34:45 +05:30
Ankush Menat
b5218096e1 perf: reduce one redis call for redis_cache 2024-12-17 18:04:43 +05:30
Ankush Menat
ad0e8ed735 test: frappe.init patching 2024-12-17 11:33:21 +05:30
barredterra
b2ec589390 test: make test translation independent from real ones 2024-12-12 00:57:14 +01:00
Sumit Bhanushali
91d553c9cf
Merge pull request #28363 from frappe/expr-series
fix(NamingExpression): series should be separate for different format expressions instead of global
2024-12-09 12:13:28 +05:30
Sumit Bhanushali
8233c2ffce fix: naming tests should consider pattern for generating series 2024-12-08 10:04:50 +05:30
Smit Vora
6b02484f1c
feat: bulk update docs using case when queries (#28483) 2024-12-06 11:34:25 +00:00
Akhil Narang
94fe90de66
refactor: pytz -> ZoneInfo
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-12-06 16:14:05 +05:30
Gavin D'souza
d521ac124d
style: Sort imports & move whitespaces to please ruff 2024-12-06 15:43:33 +05:30
Gavin D'souza
00163f5bf4
fix: Re-define utils to match previous behaviour 2024-12-06 15:43:33 +05:30
David Arnold
75377aaaf5
refactor(typing): type filters (#28218)
* chore(typing): type filters

* chore(typing): type filters for get_list et al

* fix: dashboard chart filter expression

* test: fix case with new-style right hand object to equality check

* chore: place new typed filter under typing verification

* chore: remove debug print statment

* chore: inverse logic of type guard

* fix: add float to filter value types

* chore: clarify value naming
2024-12-04 23:18:53 +00:00
Akhil Narang
84ef6ec677
refactor: fixup with ruff 0.8.1
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-12-04 13:18:04 +05:30
Akhil Narang
3b6ff70d76
Merge pull request #28636 from akhilnarang/separate-db-config-keys
refactor: allow setting mariadb/postgres specific root credentials in site config
2024-12-02 15:52:44 +05:30
Faris Ansari
f7c005dc09
Merge pull request #28629 from netchampfaris/autoincrement-renaming
fix: allow renaming autoincrement documents
2024-12-02 14:25:05 +05:30
Faris Ansari
d33b1ac695 chore: formatting 2024-12-02 13:40:16 +05:30
Akhil Narang
d77abb2663
refactor: allow setting mariadb/postgres specific root credentials in site config
Signed-off-by: Akhil Narang <me@akhilnarang.dev>
2024-12-02 13:24:31 +05:30