Skip to content

Commit

Permalink
test example in module PCRE was improved and extended
Browse files Browse the repository at this point in the history
  • Loading branch information
lyokha committed Mar 10, 2024
1 parent c0e0e73 commit 73fa149
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 31 deletions.
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
### 1.2.8.2

- Module *NgxExport.Tools.PCRE*.
+ Use *voidServer* from *ngx-export-tools ≥ 1.2.3*.
- Module *NgxExport.Tools.ServiceHookAdaptor*.
+ The test example was improved and extended.

### 1.2.8

- Module *NgxExport.Tools.Subrequest*.
Expand Down
66 changes: 58 additions & 8 deletions NgxExport/Tools/ServiceHookAdaptor.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : NgxExport.Tools.ServiceHookAdaptor
-- Copyright : (c) Alexey Radkov 2021-2023
-- Copyright : (c) Alexey Radkov 2021-2024
-- License : BSD-style
--
-- Maintainer : alexey.radkov@gmail.com
Expand Down Expand Up @@ -51,20 +51,27 @@ import Control.Monad
-- import qualified Data.ByteString as B
-- import qualified Data.ByteString.Lazy as L
-- import Data.IORef
-- import Control.Monad
-- import Control.Exception
-- import System.IO.Unsafe
--
-- data SecretWordUnset = SecretWordUnset
--
-- instance Exception SecretWordUnset
-- instance Show SecretWordUnset where
-- show = const \"unset\"
--
-- secretWord :: IORef ByteString
-- secretWord = unsafePerformIO $ newIORef ""
-- {-\# NOINLINE secretWord \#-}
--
-- testSecretWord :: ByteString -> IO L.ByteString
-- __/testSecretWord/__ v = do
-- s <- readIORef secretWord
-- return $ if B.null s
-- then \"null\"
-- else if v == s
-- then \"set\"
-- else \"unset\"
-- when (B.null s) $ throwIO SecretWordUnset
-- return $ if v == s
-- then \"success\"
-- else \"\"
-- 'NgxExport.ngxExportIOYY' 'testSecretWord
--
-- changeSecretWord :: ByteString -> IO L.ByteString
Expand Down Expand Up @@ -110,13 +117,13 @@ import Control.Monad
-- location \/ {
-- haskell_run __/testSecretWord/__ $hs_secret_word $arg_s;
--
-- if ($hs_secret_word = null) {
-- if ($hs_secret_word = unset) {
-- echo_status 503;
-- echo \"Try later! The service is not ready!\";
-- break;
-- }
--
-- if ($hs_secret_word = set) {
-- if ($hs_secret_word = success) {
-- echo_status 200;
-- echo \"Congrats! You know the secret word!\";
-- break;
Expand Down Expand Up @@ -181,6 +188,49 @@ import Control.Monad
--
-- Our secret is still intact! This is because service hooks manage new worker
-- processes so well as those that were running when a hook was triggered.
--
-- Note, however, that the order of service hooks execution in a restarted
-- worker process is not well-defined which means that hooks that affect the
-- same data should be avoided. For example, we could declare another service
-- hook to reset the secret word.
--
-- ==== File /test_tools_extra_servicehookadaptor.hs/: reset the secret word
-- @
-- resetSecretWord :: ByteString -> IO L.ByteString
-- __/resetSecretWord/__ = const $ do
-- writeIORef secretWord \"\"
-- return \"The secret word was reset\"
-- 'NgxExport.ngxExportServiceHook' \'resetSecretWord
-- @
--
-- ==== File /nginx.conf/: new location /\/reset_sw/ in server /main/
-- @
-- location \/reset_sw {
-- allow 127.0.0.1;
-- deny all;
--
-- haskell_service_hook __/resetSecretWord/__ $hs_hook_adaptor;
-- }
-- @
--
-- Both /changeSecretWord/ and /resetSecretWord/ alter the /secretWord/ storage.
-- The order of their execution in a restarted worker process is not defined,
-- and therefore the state of /secretWord/ can get altered in the new worker.
--
-- To fix this issue in this example, get rid of hook /resetSecretWord/ and use
-- directive /rewrite/.
--
-- ==== File /nginx.conf/: reset the secret word by /rewrite/
-- @
-- location \/reset_sw {
-- allow 127.0.0.1;
-- deny all;
--
-- rewrite ^ \/change_sw last;
-- }
-- @
--
-- You may also want to add a proper message for reset in /changeSecretWord/.

hookAdaptor :: ByteString -> NgxExportService
hookAdaptor = ignitionService $
Expand Down
67 changes: 60 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1684,20 +1684,27 @@ import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.IORef
import Control.Monad
import Control.Exception
import System.IO.Unsafe

data SecretWordUnset = SecretWordUnset

instance Exception SecretWordUnset
instance Show SecretWordUnset where
show = const "unset"

secretWord :: IORef ByteString
secretWord = unsafePerformIO $ newIORef ""
{-# NOINLINE secretWord #-}

testSecretWord :: ByteString -> IO L.ByteString
testSecretWord v = do
s <- readIORef secretWord
return $ if B.null s
then "null"
else if v == s
then "set"
else "unset"
when (B.null s) $ throwIO SecretWordUnset
return $ if v == s
then "success"
else ""
ngxExportIOYY 'testSecretWord

changeSecretWord :: ByteString -> IO L.ByteString
Expand Down Expand Up @@ -1744,13 +1751,13 @@ http {
location / {
haskell_run testSecretWord $hs_secret_word $arg_s;
if ($hs_secret_word = null) {
if ($hs_secret_word = unset) {
echo_status 503;
echo "Try later! The service is not ready!";
break;
}
if ($hs_secret_word = set) {
if ($hs_secret_word = success) {
echo_status 200;
echo "Congrats! You know the secret word!";
break;
Expand Down Expand Up @@ -1829,6 +1836,52 @@ Congrats! You know the secret word!
Our secret is still intact! This is because service hooks manage new worker
processes so well as those that were running when a hook was triggered.

Note, however, that the order of service hooks execution in a restarted
worker process is not well-defined which means that hooks that affect the
same data should be avoided. For example, we could declare another service
hook to reset the secret word.

###### File *test_tools_extra_servicehookadaptor.hs*: reset the secret word

```haskell
resetSecretWord :: ByteString -> IO L.ByteString
resetSecretWord = const $ do
writeIORef secretWord ""
return "The secret word was reset"
ngxExportServiceHook 'resetSecretWord
```

###### File *nginx.conf*: new location */reset_sw* in server *main*

```nginx
location /reset_sw {
allow 127.0.0.1;
deny all;
haskell_service_hook resetSecretWord $hs_hook_adaptor;
}
```

Both *changeSecretWord* and *resetSecretWord* alter the *secretWord* storage.
The order of their execution in a restarted worker process is not defined,
and therefore the state of *secretWord* can get altered in the new worker.

To fix this issue in this example, get rid of hook *resetSecretWord* and use
directive *rewrite*.

###### File *nginx.conf*: reset the secret word by *rewrite*

```nginx
location /reset_sw {
allow 127.0.0.1;
deny all;
rewrite ^ /change_sw last;
}
```

You may also want to add a proper message for reset in *changeSecretWord*.

#### Module *NgxExport.Tools.Subrequest*

Using asynchronous variable handlers and services together with the HTTP
Expand Down
2 changes: 1 addition & 1 deletion ngx-export-tools-extra.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: ngx-export-tools-extra
version: 1.2.8.1
version: 1.2.8.2
synopsis: More extra tools for Nginx Haskell module
description: More extra tools for
<https://github.com/lyokha/nginx-haskell-module Nginx Haskell module>.
Expand Down
6 changes: 3 additions & 3 deletions test/ServiceHookAdaptor/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ http {
location / {
haskell_run testSecretWord $hs_secret_word $arg_s;

if ($hs_secret_word = null) {
if ($hs_secret_word = unset) {
echo_status 503;
echo "Try later! The service is not ready!";
break;
}

if ($hs_secret_word = set) {
if ($hs_secret_word = success) {
echo_status 200;
echo "Congrats! You know the secret word!";
break;
Expand All @@ -55,7 +55,7 @@ http {
allow 127.0.0.1;
deny all;

haskell_service_hook resetSecretWord $hs_hook_adaptor;
rewrite ^ /change_sw last;
}
}
}
Expand Down
29 changes: 17 additions & 12 deletions test/ServiceHookAdaptor/test_tools_extra_servicehookadaptor.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,36 @@ import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.IORef
import Control.Monad
import Control.Exception
import System.IO.Unsafe

data SecretWordUnset = SecretWordUnset

instance Exception SecretWordUnset
instance Show SecretWordUnset where
show = const "unset"

secretWord :: IORef ByteString
secretWord = unsafePerformIO $ newIORef ""
{-# NOINLINE secretWord #-}

testSecretWord :: ByteString -> IO L.ByteString
testSecretWord v = do
s <- readIORef secretWord
return $ if B.null s
then "null"
else if v == s
then "set"
else "unset"
when (B.null s) $ throwIO SecretWordUnset
return $ if v == s
then "success"
else ""
ngxExportIOYY 'testSecretWord

changeSecretWord :: ByteString -> IO L.ByteString
changeSecretWord s = do
writeIORef secretWord s
return "The secret word was changed"
return $ L.concat ["The secret word was "
,if B.null s
then "reset"
else "changed"
]
ngxExportServiceHook 'changeSecretWord

resetSecretWord :: ByteString -> IO L.ByteString
resetSecretWord = const $ do
writeIORef secretWord ""
return "The secret word was reset"
ngxExportServiceHook 'resetSecretWord

0 comments on commit 73fa149

Please sign in to comment.