Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QSD caching potential fix #196

Merged
merged 56 commits into from
Dec 18, 2011
Merged

QSD caching potential fix #196

merged 56 commits into from
Dec 18, 2011

Conversation

gkanwar
Copy link
Member

@gkanwar gkanwar commented Dec 7, 2011

This is the fix I have right now. In the javascript it makes an additional AJAX request to the varnish_purge page that I created. This page then purges the correct page from the cache.

The gaping hole is that varnish_purge is currently accessible by anybody. I couldn't think of a good way to limit it to the correct subset of people. If I made it admin required, then anybody who could edit QSD but wasn't an admin would have issues (I don't know if there's any of these users, or if this contingency should be handled at all... if not then this is probably the best solution). If I made it based on qsd editing userbits, then it would take a perfectly general function and make it very restricted. If I made it just check for logged in, then any student could purge any page.

Any thoughts on good ways to resolve this?

Thanks!

@pteromys
Copy link
Contributor

pteromys commented Dec 7, 2011

Initially, you had a call to purge_page() in both qsd() and ajax_qsd(). Why'd you remove it from ajax_qsd? Did it not work or something?

I'm thinking that if it works, we can use it for QSD pages and the more general varnish_purge page for everything else. Arguably "everything else" does in fact need an admin to approve it.

Our website allows (allowed?) teachers to create per-class QSD pages (for class websites), so there are in fact occasions for non-admins to be editing QSD pages.

@aseering
Copy link
Member

aseering commented Dec 7, 2011

For the specific permissions question, you could always do "admin or has QSD-editing bits" :-)

Also, as pteromys already sort of pointed out implicitly, it's quite possible to wrap a general function in other functions that do permissions-checking. As one example, see "def catalog()" in esp/esp/program/modules/handlers/studentclassregmodule.py. (The general function is actually catalog_render().) That tries to put everything in one view; having multiple views for different purposes / user types works too.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 8, 2011

In response to Andrew's comment, I removed it from ajax_qsd because it didn't work. The reason it didn't work was that I couldn't figure out getting the URL that needed to be purged from within the function. I then realized that I could do it by calling a view from JS, so I implemented it that way instead. If there's a good way to get the URL that needs to be purged I could do that instead, and it would probably be neater.

In response to Adam, I didn't think about doing both for some reason. Regarding wrapping general functions in functions with permissions checking, that's essentially what I'm going currently. Purge_page is a general function. The Varnish purge view, which is publicly exposed should do the permissions checking before calling purge_page for the actual functionality.

Gurtej Kanwar added 7 commits December 8, 2011 23:51
It currently has issues testing for administrator. I'm guessing a
syntax error. I also removed the giant comment in qsd.js.
It seems like authentication works. It essentially just checks to
see if the user is either an administrator or has QSD editing bits.

Tests will be written.
@gkanwar
Copy link
Member Author

gkanwar commented Dec 9, 2011

I think I'm thoroughly confused by rebasing. Can someone please explain it to me? I looked it up online and it made sense. Then I tried to practically apply it and got really confused.

I think I my changes were committed correctly though. I think I have authentication working. I plan to write tests for this whole thing next, but I wanted someone to look it over meanwhile and make sure I didn't do something stupid.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 9, 2011

I just realized that testing this would required setting up selenium on the buildbot tests servers. Should I go ahead and do this?

@gkanwar
Copy link
Member Author

gkanwar commented Dec 9, 2011

Ummm... so turns out hippo doesn't have anything on the ebs1 partition anymore... did we lose access to this for some reason or something? (As a result the build slave wasn't running on hippo anymore)

The build slave also wasn't running on diogenes anymore, but I restarted it and currently it's testing. We'll see if it succeeds. If I get testing working again, then I'll concentrate on setting up slave2 with varnish so I can do some testing with caching.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 9, 2011

Although on second thoughts my tests don't really require varnish. I could just put up something that receives the PURGE request and returns some packet with no content but the proper headers (I think) and it should still succeed in Django. In the end I think having Varnish set up would probably be a good idea for testing.

@aseering
Copy link
Member

aseering commented Dec 9, 2011

"hippo": That's quite odd... I'd send mail to web-team@; there are a bunch of people on that list but not this who might know.

If you could set up selenium on the buildbot servers, though, that'd be great.

Are you still confused about rebasing? The idea is basically that you take a stack of diffs and apply them one by one as patches to another branch. (The stack of diffs is constructed from a series of commits on some other branch.) It's often simpler to merge instead of rebasing, though both are useful tools to know how to use.

Still need to finish writing the test. Finding the location of
some things also needs to be done.
@gkanwar
Copy link
Member Author

gkanwar commented Dec 9, 2011

Re: hippo - good idea, I sent out the email

Do you mean varnish? I got a varnish server running (I think) correctly on slave2 on Diogenes. I'm in the process of writing a test for QSD caching which would involve testing against the Varnish server. Once I have this running on my own computer and commit, we can see if the auto tester works with it or not.

Re: rebasing - I think I understood the general concept, just not how to practically apply it. I ran git rebase -i main (IIRC) and that did something. Then I tried to push to github and it said that there were conflicts needing to be resolved. I went in and it looked like the code in HEAD had the lastest and the conflicting code from my end was out of date for some reason. I resolved the conflicts and it then committed correctly. I don't know why this would be the case, and I think I might have missed something when I ran it, because it didn't really give me any option to like combine commits, change the comments, and generally anything that Andrew mentioned is a good idea to do with this...

@gkanwar
Copy link
Member Author

gkanwar commented Dec 10, 2011

It looks like hippo was restarted at some point, so the drive got unmounted and buildbot wasn't running anymore. I remounted the drive and restarted the buildslave. I may need to tweak a little bit to get testing working again.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 10, 2011

So as I was writing tests I ran into the issue of how to check that the AJAX request to purge the page actually returns the correct value. Then I realized there were really two separate tests here. One to test if the QSD page correctly calls purge_page, and one that tests purge_page and varnish_purge and makes sure they correctly purge.

With regards to the latter, I don't know how to test whether an AJAX request returned correctly. I could maybe use httplib and send a post command in order to get the return status. Or I could run some javascript in the webdriver. I'm not what the best option is here.

With regards to checking if the right AJAX request occurs, I don't know how to test this at all. One really really hackish way of doing this could be to have the call to the view set some javascript flag, and then check this. I don't really like this idea (I already did it in my csrf selenium test and I'm thinking of trying to do it a different way at some point).

Any thoughts on this?

@aseering
Copy link
Member

With regard to the latter, rather than using httplib, that sounds like a great use for Django's built-in test client.

With regard to testing this feature overall: Personally, I as a user am not too worried if purge_page returns the right value, or if the AJAX request went through as expected, etc. What I do care about is whether the site immediately reflects my changes. So I think it'd be reasonable to have a test that simply updates a page that's cached and then tries to access that page to see if it contains whatever new text was added. If it does, then regardless of how the intermediate machinery works, it must be doing something right... I'm not sure whether you can get at HTTP headers through Selenium?, but I believe I remember that there's a header that indicates whether a page is coming from a cache, so you can be sure that it's not just a complete lack of caching.

If you do that and you do a simple test of purge_cache with the Django test client, I think (unless I'm missing something?) that's pretty close to a guarantee that everything's working as expected; good enough, I think, given the cost in hackery to doing something more precise.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 11, 2011

Ah I forgot about Django's test client. Yes that's perfect for testing purge_page.

With regards to QSD, that makes sense. I'll work on implementing this tonight.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 11, 2011

Gah! So in the process of writing the test I ran into a general issue. Django itself caches objects, which means it affects this. Here's the scenario:

  1. Just django running, no varnish
  2. Log in as an admin, edit the qsd, click somewhere. The text will have changed.
  3. Refresh. The text is back to the old test.
  4. Wait a minute or two. Refresh. The text now is the new text.

This makes it impossible to test via selenium. Also I was fairly certain I wasn't having this issue before but all of a sudden I am. Any thoughts as to why this is coming up/fixes?

@gkanwar
Copy link
Member Author

gkanwar commented Dec 11, 2011

I take back the "I wasn't having this issue before". This may have always been the case now that I think back on it.

I have a test that theoretically should work. Currently it's
failing because Django's caching is getting in the way. I posted
a comment to Github, waiting for a response.

I also moved some of the common selenium testing functions out of
the specific CSRF selenium test class and into the general module.
The CSRF test now just includes and uses the functions (and still
works). My new test for QSD caching uses these as well.
@aseering
Copy link
Member

hm... I don't see this issue on my dev server. I also don't see anything in the code that would cause this issue. (Django itself does no caching; it provides infrastructure to help implement caching, but it leaves the implementation up to us. It doesn't immediately look like any of the relevant functions, in esp/qsd/views.py, are even @cache_function'ed. They are @cache_control'ed, but that simply sets an HTTP header for Varnish.)

Can you reproduce with a straight-up dev server, no intermediate Varnish or Squid?

@gkanwar
Copy link
Member Author

gkanwar commented Dec 15, 2011

Apparently the change hadn't been taken into account, so I just incorporated it into this other commit. At this point I think this pull request is complete.

Btw, when looking at inline qsd, it's failing for me with no proxy cache at all. When I change

CACHE_BACKEND = "esp.utils.memcached_multikey://127.0.0.1:11211/?timeout=%d" %$

to

#CACHE_BACKEND = "esp.utils.memcached_multikey://127.0.0.1:11211/?timeout=%d" %$
CACHE_BACKEND = "dummy:///"

it works again. This seems to be some sort of Django caching. Adam, you said there was no Django caching by default, but that it has the framework for specifying some caching. Do we normally not specify caching? It might be that I set up my dev server wrong so it does cache using memcached for Django.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 15, 2011

... and I take that back. After looking more deeply, my solution with stripping all cookies but the session doesn't work. We don't want the page to be cached per user in any way. Deleting the cookies, however, does result in the page not thinking it's logged in, namely that the admin portions don't display.

I guess there's several options that I can think of.

  1. Cache the entire page (not on a per user basis), make the parts that show up only for admins be always on the page but hidden, and display only in the case of admin OR qsd editor (before we had this but it only displayed on admin, I changed this to use template stuff, so now it's affected by caching)
  2. Cache the page in pieces (using ESI, ex.). This way our different pieces could be cached per-user or not independently, but it still takes advantage of caching the HTML itself. I like this idea, but the it probably takes too long to implement in time.
  3. No caching?? We probably shouldn't do this.

@aseering
Copy link
Member

For what it's worth, MIT's site already does (1) on this list. Or at least, has templates that can handle (1); stuff is always on the page and always the same for all users but is hidden based on some JavaScript/cookie magic.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 15, 2011

Yeah, (1) would be pretty easy to implement. What was already in place was similar to this, except the visibility was only based on admin, so people with QSD bits but who were not admins didn't get the hidden stuff to show up, even though they still could edit it. I might try to go through and change it to this, though I don't think I can get this fully working before the Dec 15 deadline. Should I go ahead and try anyway?

Previously, inline QSD editing had checked whether or not the user
was an admin to determine whether or not to show the edit header.
This was a problem because users which were not admins but had QSD
editing bits would not see this even though they were able to edit
QSD.

I fixed this by adding another cookie, cur_qsd_bits, and two new
css classes, qsd_bits and qsd_bits_hidden, which are analogous to
cur_admin, admin, and admin_hidden respectively. The editing
header now appears correctly for users with QSD bits but not admin
privileges.
@gkanwar
Copy link
Member Author

gkanwar commented Dec 15, 2011

Well that was easier than expected. I think I have it working (and my test doesn't break! :D).

I'm going to go through tomorrow and simplify my qsd caching test to account for this. Also maybe write a test for this feature itself.

Oh, also the loginbox seems to break when cached with the cookies stripped (since it's AJAX, it should show it as logged in once the page is rendered, because it has the cookies then). I might look into this.

Gurtej Kanwar added 3 commits December 15, 2011 23:02
...again. I did something with git rebase earlier that undid this
I think, so I redid this. I'm putting it in this branch because
my test depends on this.
The tests now test for both inline and regular QSD. They also pass.

I was having authentication issues before which I fixed as well. I
had some boolean logic messed up.
@gkanwar
Copy link
Member Author

gkanwar commented Dec 16, 2011

Fixed up my test to a point that I'm satisfied with it.

I also redid the change that moved commonly used seltest functions to the general seltests module.

I also noticed that the "Edit Page" link showed up at the bottom of QSD no matter whether you were logged in or not. I fixed this to use the Javascript hidden QSD stuff that I did eariler.

The login box still doesn't work, and I didn't bother trying to fix it. If Mike is working on redoing the default site, this is probably getting fixed/changed.

@aseering
Copy link
Member

Well, that's a whole bunch of commits!

I think this branch looks reasonable to me.

Andrew, any further comments?

Otherwise "day then merge".

@aseering
Copy link
Member

Actually, sorry, I didn't read my own comments: There's still a bug here, that I'd really like to see resolved first, since it's both simple and causes things to not work on non-MIT sites.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 17, 2011

I actually had nothing to do with that commit. That was a commit that Mike made at some point that got included through rebasing (or rather failing thereof).

@aseering
Copy link
Member

Ah, ok. Sorry; having trouble picking out whose commit was whose, with this UI...

Michael, thoughts? Has this been fixed?

@pricem
Copy link
Contributor

pricem commented Dec 18, 2011

This pull request contains some commits (and associated comments) from my onsite work leading up to MIT Splash. I'll address those in a separate pull request.

It sounds like this one is ready to go; we'll have to do some careful testing, but I think this is best done after a merge.

@aseering
Copy link
Member

In that case, I'll go ahead and merge :-)

Michael, I think I'd argue for fixing at least this issue for SR1, since it makes the particular feature entirely unuseful for programs that aren't MIT Splash 2010. (Or just remove that codepath altogether, so that it doesn't trip anyone up somehow.) Thoughts on a minor late addition there?

aseering added a commit that referenced this pull request Dec 18, 2011
@aseering aseering merged commit 22bd750 into main Dec 18, 2011
@pricem
Copy link
Contributor

pricem commented Dec 19, 2011

To respond to an earlier comment on this thread, in case it wasn't already clear: The cache_inclusion_tag decorator has already been converted to use the caching API; this was done back around February. So when you use cache_inclusion_tag you can specify cache dependencies like '[name_of_tag].cached_function.depend_on_...'; see esp/esp/program/templatetags/class_render.py for examples

@pricem pricem mentioned this pull request Dec 19, 2011
@jmoldow
Copy link
Member

jmoldow commented Dec 27, 2011

We will need to install selenium on diogenes.learningu.org and esp.mit.edu (if this hasn't already been done; I haven't been following Gurtej's work with selenium) before deploying this to live sites. We should also update INSTALL and dev_server_setup.sh to reflect this new dependency.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 27, 2011

It has been added to INSTALL and dev_server_setup.sh (though you guys should check it over), and I think I set it up on diogenes.learningu.org, but not esp.mit.edu so far.

@jmoldow
Copy link
Member

jmoldow commented Dec 27, 2011

Can you point me to the commit where it was added? I don't see it.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 27, 2011

Looks like these ones do it:
ae596a0
6409774
e95271f

@jmoldow
Copy link
Member

jmoldow commented Dec 27, 2011

Thanks!

I see the error of my ways now. I was typing 'git grep -n "selenium"' while I was in esp/esp, so I wasn't seeing esp/INSTALL or esp/useful_scripts.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 27, 2011

Ah that would make sense :P

@pteromys
Copy link
Contributor

If you're looking for changes in a specific file, you can also type git blame to see the last commit that modified each line. Hit / (forward slash) while you're in less (you do have that set as your pager, right?) to search.

I use this all the time to track the history of bits of code that look like they shouldn't work.

@gkanwar
Copy link
Member Author

gkanwar commented Dec 27, 2011

Yeah, I was actually going to use that to find this until I realized that just looking at the commit history of the file would be easier, but git blame is pretty useful overall.

willgearty added a commit that referenced this pull request Jan 28, 2021
willgearty added a commit that referenced this pull request May 27, 2021
* Initial docs for stable release 13

* Docs for #3116, #3117, and #3118

* Added docs about django upgrade

* Docs for #3128

* Docs for #3129, #3133, #3134, and #3137

* Docs for #3156 and #3153

* Docs for #3174, #3163, and #3184

* Docs for #3139, #3140, and #3141

* Docs for #3143, #3150, #3154, #3160, #3162, and #3168

* Docs for #3171, #3185, #3186, and #3188

* Docs for #3131 and #3189

* Docs for #3149 and #3190

* Docs for #3193, #3194, #3195, #196, and #3197

* Clarification

* Docs for #3192, #3201, #3209, and #2248

* Docs for #3204, #3212, #3214, #3205, 9fd073c, and #3226

* Docs for #3232, de5861c, #3231, #3233, #3234, #3237, #3238, and #3239

* Fix indent

* Docs for #3227 and #3235

* Add missing word

* spelling

* Docs for e57581f, #3255, #3253, #3257, and #3249

* Docs for #3254, #3260, and #3262

* Docs for #3263, #3272, #3240, #3264, #3266, and #3270

* clarifications

* Docs for #3283 and #3252

* Docs for #3288 and misc commits

* Docs for #3292, #3311, #3286, #3289, and #3279

* Docs for a377f0d; move note

* Docs for #3315, #3290, and #3322

* Docs for #3273 and #3317

* Final edits
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants