Handling Lua errors in a clean and effective manner - error-handling

I'm currently trying to code an add-on the popular game World Of Warcraft for a friend. I don't understand too much about the game myself and debugging it within the game is difficult as he's having to do all the testing.
I'm pretty new to Lua, so this may be a very easy question to answer. But when a Lua error occurs in WoW it throws it on screen and gets in the way, this is very bad to a game player as it will stop their gameplay if it throws the exception at the wrong time. I'm looking for a way to cleanly handle the error being thrown. Here's my code so far for the function.
function GuildShoppingList:gslSlashProc()
-- Actions to be taken when command /gsl is procced.
BankTab = GetCurrentGuildBankTab()
BankInfo = GetGuildBankText(BankTab)
local Tabname, Tabicon, TabisViewable, TabcanDeposit, TabnumWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(BankTab)
p1 = BankInfo:match('%-%- GSL %-%-%s+(.*)%s+%-%- ENDGSL %-%-')
if p1 == nil then
self:Print("GSL could not retrieve information, please open the guild bank and select the info tab allow data collection to be made")
else
self:Print("Returning info for: "..Tabname)
for id,qty in p1:gmatch('(%d+):(%d+)') do
--do something with those keys:
local sName, sLink, iRarity, iLevel, iMinLevel, sType, sSubType, iStackCount = GetItemInfo(id);
local iSum = qty/iStackCount
self:Print("We need "..sLink.." x"..qty.."("..iSum.." stacks of "..iStackCount..")")
end
end
end
The problem being when checking to see if p1 is nil, it still throws a Lua error about trying to call p1 as nil. It will be nil at times and this needs to be handled correctly.
What would be the correct most efficient way to go about this?

You might want to wrap your function in a pcall or xpcall which enables you to intercept any error thrown by Lua.
Aside of that, I personally find this construct easier to read:
p1=string.match(str,pat)
if p1 then
-- p1 is valid, eg not nil or false
else
-- handle the problems
end

Related

WebSphere wsadmin testConnection error message

I'm trying to write a script to test all DataSources of a WebSphere Cell/Node/Cluster. While this is possible from the Admin Console a script is better for certain audiences.
So I found the following article from IBM https://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/txml_testconnection.html which looks promising as it describles exactly what I need.
After having a basic script like:
ds_ids = AdminConfig.list("DataSource").splitlines()
for ds_id in ds_ids:
AdminControl.testConnection(ds_id)
I experienced some undocumented behavior. Contrary to the article above the testConnection function does not always return a String, but may also throw a exception.
So I simply use a try-catch block:
try:
AdminControl.testConnection(ds_id)
except: # it actually is a com.ibm.ws.scripting.ScriptingException
exc_type, exc_value, exc_traceback = sys.exc_info()
now when I print the exc_value this is what one gets:
com.ibm.ws.scripting.ScriptingException: com.ibm.websphere.management.exception.AdminException: javax.management.MBeanException: Exception thrown in RequiredModelMBean while trying to invoke operation testConnection
Now this error message is always the same no matter what's wrong. I tested authentication errors, missing WebSphere Variables and missing driver classes.
While the Admin Console prints reasonable messages, the script keeps printing the same meaningless message.
The very weird thing is, as long as I don't catch the exception and the script just exits by error, a descriptive error message is shown.
Accessing the Java-Exceptions cause exc_value.getCause() gives None.
I've also had a look at the DataSource MBeans, but as they only exist if the servers are started, I quickly gave up on them.
I hope someone knows how to access the error messages I see when not catching the Exception.
thanks in advance
After all the research and testing AdminControl seems to be nothing more than a convinience facade to some of the commonly used MBeans.
So I tried issuing the Test Connection Service (like in the java example here https://www.ibm.com/support/knowledgecenter/en/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/cdat_testcon.html
) directly:
ds_id = AdminConfig.list("DataSource").splitlines()[0]
# other queries may be 'process=server1' or 'process=dmgr'
ds_cfg_helpers = __wat.AdminControl.queryNames("WebSphere:process=nodeagent,type=DataSourceCfgHelper,*").splitlines()
try:
# invoke MBean method directly
warning_cnt = __wat.AdminControl.invoke(ds_cfg_helpers[0], "testConnection", ds_id)
if warning_cnt == "0":
print = "success"
else:
print "%s warning(s)" % warning_cnt
except ScriptingException as exc:
# get to the root of all evil ignoring exception wrappers
exc_cause = exc
while exc_cause.getCause():
exc_cause = exc_cause.getCause()
print exc_cause
This works the way I hoped for. The downside is that the code gets much more complicated if one needs to test DataSources that are defined on all kinds of scopes (Cell/Node/Cluster/Server/Application).
I don't need this so I left it out, but I still hope the example is useful to others too.

MPI_Test isn't picking up a completed MPI_Send

I've spent three days looking for an answer so I hope you'll bear with me if this has already been addressed and I've been mighty unlucky finding a solution.
I'm using Fortran (eugh!) but this is a generic MPI query.
Scenario (simplified for this example):
Processes 0 and 1 communicate with process 2 (but not with each other)
0 & 1 do lots of sends/receives
2 does lots of receives/process/sends (but each pair is done twice so as to
pick up both 0 & 1)
0 & 1 will eventually stop - I know not when! - so I do an MPI_Send from each when appropriate using the rank of the 3rd process (filter_rank_id=2) and a special tag (c_tag_open_rcv=200), with a logical TRUE in the buffer (end_of_run). Like this:
CALL MPI_SEND(end_of_run, 1, MPI_LOGICAL, filter_rank_id, c_tag_open_rcv, mpi_coupling_comms, mpi_err)
The problem arises in process 2... it's busy doing its MPI_Recv/MPI_Send pairs and I cannot break out of it. I have set up a non-blocking receive for each of the other two processes and stored the request handles:
DO model_rank_id= 0, 1
!Set up a non-blocking receive to get notification of end of model run for each model
end_run = end_model_runs(model_rank_id) !this is an array of booleans initialised to FALSE
CALL MPI_IRECV(end_run, 1, MPI_LOGICAL, model_rank_id, &
c_tag_open_rcv, coupling_comms, mpi_request_handle, mpi_err)
!store the handle in an array
request_handles(model_rank_id) = mpi_request_handle
END DO
where model_rank_id is the process number in the MPI communicator i.e. 0 or 1.
Later on, busy doing all those receive/send pairs, I always check whether anything's arrived in the buffer:
DO model_rank_id= 0, 1
IF (end_model_runs(model_rank_id) .EQV. .FALSE.) THEN
CALL MPI_TEST(request_handles(model_rank_id), run_complete, mpi_status, mpi_err)
IF (run_complete .eqv. .FALSE.) THEN
!do stuff... receive/process/send
ELSE
!run is complete
!___________removed this as I realised it was incorrect__________
!get the stop flag for the specific process
CALL MPI_RECV(end_run, 1, MPI_LOGICAL, model_rank_id, &
c_tag_open_rcv, coupling_comms, mpi_err)
!____________end_________________________________________________
!store the stop flag so I can do a logical 'AND' on it and break out when
!both processes have sent their message
end_model_runs(model_rank_id) = end_run
END IF
END IF
END DO
Note that this snippet is contained in a loop which carries on until all the stop flags are TRUE.
I know it's fairly complex, but this can't be that hard, can it? If anyone can see the error that'd be fantastic, or even suggest a better way to do it.
Huge thanks in advance.
Your program is probably stuck in the MPI_RECV call. The reason is that having a positive completion flag as returned by MPI_TEST means that MPI_IRECV has received the message. Unless the sender sends another message with the same tag, MPI_RECV will simply block and wait, in your case probably indefinitely. Apart from that, you are issuing two MPI_IRECV calls with the same receive buffer which is probably not what you really want to do since end_run = end_model_runs(model_rank_id) does not copy the address of the array element into end_run but rather its value.
Your code should look like this:
DO model_rank_id= 0, 1
!Set up a non-blocking receive to get notification of end of model run for each model
CALL MPI_IRECV(end_model_runs(model_rank_id), 1, MPI_LOGICAL, model_rank_id, &
c_tag_open_rcv, coupling_comms, request_handle, ierr)
!store the handle in an array
request_handles(model_rank_id) = request_handle
END DO
...
DO model_rank_id= 0, 1
IF (end_model_runs(model_rank_id) .EQV. .FALSE.) THEN
CALL MPI_TEST(request_handles(model_rank_id), run_complete, status, ierr)
IF (run_complete .eqv. .FALSE.) THEN
!do stuff... receive/process/send
ELSE
!run is complete
!the stop flag is ALREADY in end_model_runs(model_rank_id)
!do a logical 'AND' on it and break out when
END IF
END IF
END DO
As a side note, using your own identifiers that start with mpi_ is a terrible idea since those might clash with symbols provided by the MPI library. You should really treat mpi_ as a reserved prefix and never use it while naming your own variables, subroutines, etc. I've fixed that for you in the code above.
I solved this eventually after a lot of experimentation, it was actually quite simple (isn't it always?)
The problem was due to the fact that processes 0 & 1 could end and post their "I'm finished" messages OK, but process 2 was in such a tight loop doing the test and recv/send pair (the outer loops on both sets of send/recv's omitted for clarity in original past), that the test would fail and the process would stick in the blocking MPI_RECV.
First I tried a sleep(3) which made it work, but it couldn't sleep on every loop without really bad effects on perfomance, then I tried an MPI_IPROBE but hit the same problem as the test. In the end, a timeout around the MPI_IPROBE did the trick, thus:
DO iter1 = 1, num_models
!Test each model in turn and ensure we do the comms until it has finished
IF (end_model_runs(iter1) .EQV. .FALSE.) THEN
model_rank_id= models(iter1)
now = TIME()
DO WHILE (TIME() .LT. now + timeout)
msg_flag = .FALSE.
CALL MPI_IPROBE(model_rank_id, c_tag, coupling_comms, &
msg_flag, empi_status, empi_err)
IF (msg_flag .EQV. .TRUE.) THEN
!Message waiting
EXIT
END IF
END DO
IF (msg_flag .EQV. .TRUE.) THEN
CALL MPI_RECV(state_vector, num_state_params, MPI_DOUBLE_PRECISION, &
model_rank_id, c_tag, coupling_comms, empi_status, empi_err)
ELSE !no message waiting, flag should be False, i.e. the run *has* finished
end_model_runs(iter1) = .NOT. msg_flag
END IF
END IF
END DO
and this code inside a loop which breaks once all the members of end_model_runs are TRUE.
I hope this helps someone else - and saves them three days of effort!

Getting "Can not convert the given object to query." with ColdFusion ORM

This is happening intermittently (usually at start up). I get the above error message when executing the following code.
var arr = ORMExecuteQuery( "FROM priority WHERE active = 1 ORDER BY sortOrder" );
var qry = entityToQuery( arr );
The first line executes fine, but the second line blows up. The solution is to run ormreload();
The problem keeps coming up in an unpredictable way though. Even when no changes have been made to the beans or gateways that are using ORM. Completely unpredictable and impossible to replicate on purpose. Is there something else that can mess with the hibernate mappings that could cause this type of problem.
Other info that may be pertinent:
This is a MURA plugin based on a recent version of FW/1.
ormreload() is a persistent fix (until it fails again)
My current solution is to put ormreload() in the setupApplication() method of application.cfc
I just want to understand better what could be causing this problem.

Does exception handling in Clarion exist?

Does Clarion 8 offer anything for exception handling? I know as of Clarion 5 there was no support for things like try / catch but that was released almost 10 years ago. I can't seem to find any info on how to recover from exceptions in C6 to C8 unless I was using Clarion# (aka Clarion.NET) which I'm not. If there's definitely nothing like try / catch, are there any tricks or hacks that can be used to not have a program crash when an exception is thrown even if it goes unhandled?
If it helps, I'm using version 8.0.0.8778.
EDIT 1:
Here is some sample code for a basic program that should supposedly illustrate the feature PROP:LastChanceHook, however, I can't get it to work. When I run this program, I see the first message "Start", but then nothing happens. I've tried returning 0 or 1 from Hook but that hasn't made a difference either. Every time I run this, I have to go onto the Task Manager and end the process for the program because it's not being killed.
PROGRAM
INCLUDE('CWEXCPT.INT'), ONCE
MAP
Hook(*ICWExceptionInfo), LONG
Test(LONG,LONG)
END
CODE
MESSAGE('[Sample] Start')
SYSTEM{PROP:LastChanceHook} = ADDRESS(Hook)
Test(10, 0) ! Intentionally causes an exception
MESSAGE('[Sample] After Test')
RETURN ! Tried removing this, no difference
Hook PROCEDURE(*ICWExceptionInfo info)
CODE
MESSAGE('[Sample] Start Hook')
IF info &= NULL THEN RETURN 0 END
Message('An exception!')
RETURN 1 ! 0 = don't kill, anything > 0 = tell RTL to kill the thread
Test PROCEDURE (LONG a, LONG b)
CODE
a %= b
Yes, take a look at prop:LastChanceHook in the help. It may provide enough function for your needs.
In other cases, the info at this link might also be useful:
http://clarionsharp.com/blog/tracking-down-those-pesky-gpfs/
In the next public build of C8 (it's presently Sept 27, 2012), the buttons on that exception display (shown at the link above) can be customized a bit.

Transactions in Datamapper & Rails (dm-rails)

I have two models: hotel and location. A location belongs to a hotel, a hotel has one location. I'm trying to create both in a single form, bear in mind that I can't use dm-nested for nested forms due to a dependency clash.
I have code that looks like:
if (#hotel.save && #location.save)
# process
else
# back to form with errors
end
Unfortunately, #hotel.save can fail and #location.save can complete (which confuses me because I didn't think the second condition would run in an AND block if the first one failed).
I'd like to wrap these in a transaction so I can rollback the Location save. I can't seem to find a way to do it online. I'm using dm-rails, rails 3 and a postgresql database. Thanks.
The usual way to wrap database operations in DataMapper is to do something like this:
#hotel.transaction do
#hotel.save
#location.save
end
Notice that #hotel is quite arbitrary there; it could as well be #location or even a model name like Hotel.
In my experience, this works best when you enable exceptions to be thrown. Then if #hotel.save fails, it will throw an exception, which will be caught by the transaction block, causing the transaction to be rolled back. The exception is, of course, reraised.