WIP: Routine Unresponsive due to Deadlock #51

Draft
modulatingforce wants to merge 10 commits from issue-routine-lock into routines-functionality
3 changed files with 72 additions and 12 deletions
Showing only changes of commit 4719b93ce5 - Show all commits

View file

@ -52,10 +52,33 @@ impl ExecBodyParams {
pub async fn get_channel(&self) -> Option<Channel> {
dbg!("Core > ExecBodyParams > GetChannels START");
dbg!("!! [x] Document - After SUCCESS message was sent to chat");
dbg!(">> BotActionAR - RwLock from botmodules.rs::929:46 - current_readers = 1 ");
dbg!(">> RoutineAR - RwLock from botmodules.rs::1261:32 - current_readers = 1 ");
dbg!(">> join_handle - RwLock from botmodules.rs::1226:46 - current_readers = 0 ");
dbg!(">> BotInstanceAR - RwLock from botinstance.rs::150:28 - current_readers = 2");
let curr_act = Arc::clone(&self.curr_act);
let parent_act_lock = curr_act.read().await;
let act = &(*parent_act_lock);
let curr_act_lock = curr_act.read().await;
dbg!("Core > ExecBodyParams > After Creating ExecBodyParams.current_act.read() Guard ");
dbg!("!! [x] Document - After SUCCESS message was sent to chat");
dbg!(">> BotActionAR - RwLock from botmodules.rs::929:46 - current_readers = 1 ");
dbg!(">> RoutineAR - RwLock from botmodules.rs::1261:32 - current_readers = 1 ");
dbg!(">> join_handle - RwLock from botmodules.rs::1226:46 - current_readers = 0 ");
dbg!(">> BotInstanceAR - RwLock from botinstance.rs::150:28 - current_readers = 2");
let act = &(*curr_act_lock);
dbg!("Core > ExecBodyParams > Using the Read Guard ");
dbg!("!! [x] Document - After SUCCESS message was sent to chat");
dbg!(">> BotActionAR - RwLock from botmodules.rs::929:46 - current_readers = 1 ");
dbg!(">> RoutineAR - RwLock from botmodules.rs::1261:32 - current_readers = 1");
dbg!(">> join_handle - RwLock from botmodules.rs::1226:46 - current_readers = Not Listed ");
dbg!(">> BotInstanceAR - RwLock from botinstance.rs::150:28 - current_readers = 2");
let out = match act {
BotAction::C(_) => {
// let temp = c.module.clone();
@ -72,12 +95,22 @@ impl ExecBodyParams {
// let temp = r.module.clone();
// Some(temp)
dbg!("Core > ExecBodyParams > GetChannels - routine identified");
dbg!(">> BotActionAR - RwLock from botmodules.rs::929:46 - current_readers = 1 ");
dbg!(">> RoutineAR - RwLock from botmodules.rs::1261:32 - current_readers = 1");
dbg!("!! [x] Document");
dbg!(">> BotActionAR - RwLock from botmodules.rs::930:46 - current_readers = 2");
dbg!(">> RoutineAR - RwLock from botmodules.rs::1262:32 - current_readers = 1");
dbg!(">> join_handle - RwLock from botmodules.rs::1226:46 - current_readers = 0");
dbg!(">> BotInstanceAR - RwLock from botinstance.rs::150:28 - current_readers = 3 ");
dbg!(">> BotInstanceAR - RwLock from botinstance.rs::150:28 - current_readers = 1");
// => 03.30 - Just before deadlock
let out = Some(r.read().await.channel.clone());
// dbg!("ISSUE : RoutineAR - RwLock from botmodules.rs::1261:32 - current_readers = 1");
// let out = Some(r.read().await.channel.clone());
let guard = r.read().await;
dbg!("ISSUE> Never makes it after the read guard");
let channel = guard.channel.clone();
drop(guard);
let out = Some(channel);
// => 03.30 - This isn't reached because of the Deadlock
dbg!(">> Just after Potential Deadlock Lock");

View file

@ -507,6 +507,7 @@ pub struct BotCommand {
impl BotCommand {
pub async fn execute(&self, params : ExecBodyParams) {
// This is how BotCommand implements their Working exec_body
(*self.exec_body)(params).await;
}
}
@ -643,7 +644,7 @@ pub struct Routine {
pub name : String ,
pub module : BotModule , // from() can determine this if passed parents_params
pub channel : Channel , // Requiring some channel context
exec_body: bot_actions::actions_util::ExecBody,
exec_body: Arc<RwLock<bot_actions::actions_util::ExecBody>>,
pub parent_params : ExecBodyParams ,
pub join_handle : Option<Arc<RwLock<JoinHandle<RoutineAR>>>> ,
start_time : Option<DateTime<Local>> ,
@ -895,7 +896,7 @@ impl Routine {
module : BotModule ,
channel : Channel,
routine_attr : Vec<RoutineAttr> ,
exec_body : bot_actions::actions_util::ExecBody ,
exec_body : Arc<RwLock<bot_actions::actions_util::ExecBody>> ,
parent_params : ExecBodyParams
) -> Result<
Arc<RwLock<Routine>>,
@ -1285,17 +1286,43 @@ impl Routine {
parent_params
};
dbg!("Core > Guarding & Executing Child Execution Body");
dbg!("Core > Guarding and will Execute Child Execution Body");
dbg!(">> BotActionAR - RwLock from botmodules.rs::929:46 - current_readers = 0 ");
dbg!(">> RoutineAR - RwLock from botmodules.rs::1261:32 - current_readers = Not Listed");
dbg!(">> BotInstanceAR - RwLock from botinstance.rs::150:28 - current_readers = 3 ");
// {
// // The below starts the Read Lock that conlicts
// let guard2 = self_ar.read().await;
// dbg!("Core > Guarded & Executing Child Execution Body");
// dbg!("!! [x] Document ");
// dbg!(">> BotActionAR - RwLock from botmodules.rs::929:46 - current_readers = 0 ");
// dbg!(">> RoutineAR - RwLock from botmodules.rs::1261:32 - current_readers = 1");
// dbg!(">> BotInstanceAR - RwLock from botinstance.rs::150:28 - current_readers = 2 ");
// // this way seems to be having issues for Routine > Loopbody
// // in particular, because by this point we have a ReadGuard on Routine
// // somehow the read guard is conflicting with a read guard in the underlying
// // fn?
// (guard2.exec_body)(parent_params).await;
// drop(guard2);
// }
{
let guard2 = self_ar.read().await;
(guard2.exec_body)(parent_params).await;
let exec_body_ar = guard2.exec_body.clone();
drop(guard2);
let guard3 = exec_body_ar.read().await;
(guard3)(parent_params).await;
drop(guard3);
}
// (self_ar.read().await.exec_body)(
// parent_params
// ).await;

View file

@ -279,7 +279,7 @@ async fn countdown_chnl_v1(params : ExecBodyParams) {
module,
channel.unwrap(),
routine_attr,
exec_body,
Arc::new(RwLock::new(exec_body)),
params.clone()
).await {
let newr_ar = newr.clone();
Review

Issue with the Fix

If child Routine fn are defined as regular fn rather than async , Custom Routine fn would not be able to call Chat.say() or similar functionality

Here for example, in a Custom Routine fn innertester(params : Arc<RwLock<ExecBodyParams>> , we can't call chat.say() in this area

### Issue with the Fix If child Routine `fn` are defined as regular `fn` rather than `async` , Custom Routine `fn` would not be able to call `Chat.say()` or similar functionality Here for example, in a Custom Routine `fn innertester(params : Arc<RwLock<ExecBodyParams>>` , we can't call `chat.say()` in this area
Review

Honestly I'm favoring keeping the fox and maybe enhancing Chat so it has non-async calls for say().

Keep in mind in implementing, we cannot call async calls in a blocking context. This means if I have a non async code block, code calls (e.g. fn) cannot be awaited on. In other words in non Async fn, I cannot use client.send().await. There are ways around this though (later notes)

I don't foresee issues with multitasking here if we enhance Chat so users essentially enqueue "messages" (consisting of BotMsgType and ExecParams) then the bot has a separate tokio::task running that processes those messages (i.e., triggering the message using given twitch-irc call like client.say() )

In addition with in place, when custom module developers define a routine, they don't have to worry about locks as within the context of a custom built Routine (in theory) should be blocking

  • ofc we still need to be mindful of locks initiated and managed at core level

I'm thinking of using async-channel crate
https://docs.rs/async-channel/latest/async_channel/fn.bounded.html

Honestly I'm favoring keeping the fox and maybe enhancing `Chat` so it has non-async calls for `say()`. Keep in mind in implementing, we cannot call `async` calls in a blocking context. This means if I have a non `async` code block, code calls (e.g. `fn`) cannot be awaited on. In other words in non Async fn, I cannot use `client.send().await`. There are ways around this though (later notes) I don't foresee issues with multitasking here if we enhance `Chat` so users essentially enqueue "messages" (consisting of `BotMsgType` and `ExecParams`) then the bot has a separate `tokio::task` running that processes those messages (i.e., triggering the message using given `twitch-irc` call like `client.say()` ) In addition with in place, when custom module developers define a routine, they don't have to worry about locks as within the context of a custom built `Routine` (in theory) should be blocking - ofc we still need to be mindful of locks initiated and managed at `core` level --- I'm thinking of using `async-channel` crate https://docs.rs/async-channel/latest/async_channel/fn.bounded.html
@ -475,7 +475,7 @@ async fn test3_body(params : ExecBodyParams) {
module,
channel.unwrap(),
routine_attr,
exec_body,
Arc::new(RwLock::new(exec_body)),
params.clone()
).await;