Commit graph

2134 commits

Author SHA1 Message Date
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
Faris Ansari
3b014a2548 test: rename autoincrement document 2024-11-30 16:49:04 +05:30
David Arnold
6f35a554a5
fix: make read only mode thread safe (#28359)
* fix: Apply read_only_method decorator to Document methods

* fix: update tests for read-only document context manager

* refactor: place mappers into read-only mode

Reapply "refactor: place mappers into read-only mode"

This reverts commit a8208d57069c63f0982bf2881bcad28a4b349f3c.

read-only mode is now thread safe
2024-11-18 15:00:50 +01:00
David Arnold
d4382dc020
feat: add allowed referrers to loosen csrf prevention (#27841)
* fix: add allowed referrers to loosen csrf prevention

* feat: Add test case for is_allowed_referrer functionality
2024-11-15 12:09:53 +05:30
Akhil Narang
3dff39946d
Merge pull request #28448 from blaggacao/fix/test-environment-user-idempotency
fix(testing)!: ensure idempotency on the test environment user
2024-11-14 15:36:58 +05:30
David Arnold
057139ea2e
chore(communication): cleanup unused code (#28199)
* chore: feedback doctype no longer exists

missed from https://github.com/frappe/frappe/pull/17479

* chore: remove unused communication type

This was removed and migrated already in v12:

```
frappe/patches/v12_0/setup_comments_from_communications.py:	frappe.db.delete("Communication", {"communication_type": "Comment"})
```
... comming from 41d90fa6d1
which effectively reverted 465318878e
2024-11-14 00:12:14 +01:00
David
e2f5536f08
fix(testing): ensure idempotency on the test environment user 2024-11-13 10:42:19 +01:00
David
9954ca917b
fix: revert deprecation of json test records 2024-11-06 13:20:14 +01:00
David Arnold
4000cba810
fix: compat FrappeTestCase (#28367)
due to circular imports issues and me going out of my way to make it work 'cleanly', the previous backwards compatibility for FrappeTestCase unfortunately did not work on the manual cli test runner 'run-tests'

While not generally not affecting CI (which is precedented by the framwork's best practices to use 'run-parallel-test'), this broke some manual developer workflows

The restauration of FrappeTestCase in these scenario now unfortunately involves a plain copy of almost an entire implementation into the dumpster.

On the one hand, this doesn not accurately reflect the rather minuscule differences between IntegrationTestCase and FrappeTestCase, but on the other hand, it shields and freezes the old api should IntegrationTestCase evolve futher
2024-11-05 18:16:22 +01:00