Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Question/Bug: Expected behaviour for related updates when a Queue fails

    Hi Isomorphic,

    I'm seeing a behaviour in 12.0p, where I think it might be a bug:
    I have a operationType:custom-DSRequest, that can be sent for one or many items of a list from clientside. In case many entries are selected, the requests are sent as a queue.

    Now this request fails for some entries, which is fine in general. The problem is the handling of relatedUpdates in the non-failing requests in the queue.
    In this case the relatedUpdates of request 1 is applied in the GUI/ResultSet, while the whole transaction is rolled back serverside.

    An example where DSRequest 2 and 3 of 3 fail, while DSRequest 1 on it's own succeeds:
    • Queue-response
      • operationType:custom-DSResponse
        • status:0
        • queueStatus:-1
        • relatedUpdates: some proper relatedUpdate-record
      • operationType:custom-DSResponse
        • status:-1
        • queueStatus:-1,
        • data: my error message text
      • operationType:custom-DSResponse
        • status:-1
        • queueStatus:-1,
        • data: my error message text
    I don't think it is correct that the relatedUpdate of DSRequest 1 is applied in the GUI. If you agree, can you have a look?

    Thank you & Best regards
    Blama

    #2
    We agree, no relatedUpdates are expected to be applied if queue had failed requests. In order to address this we need more details, ideally a standalone use case, since we could not reproduce it. Thank you.

    Comment


      #3
      Hi Isomorphic,

      here is a BuiltInDS based test case.
      • Click "Reset all data to 0"" to set all salaries to 0 and show this change in data through relatedUpdates (just to show that this works in general)
      • Select some (not the first two entries) and click "Change selected to 1000" to change some salaries to 1000 and show this change in data through relatedUpdates
      • Select some - including 1st and/or 2nd - and click "Change selected to 1000" to change some salaries to 1000, which should not work
      In the 3rd case there are two problems:
      1. The one mentioned in #1 - even if the Queue fails, the GUI is updated for the not-failed requests (see Developer Console RPC Tab)
      2. Only in the testcase (at least not happening in my project using PostgreSQL): No rollback serverside before data is returned to the client, even though one request failed. The log mentions "Committing HSQLDB transaction". I'd expect an rollback.
      Best regards
      Blama

      employees.ds.xml addition:
      Code:
          <serverObject lookupStyle="new" className="com.smartgwt.sample.server.listener.Employees" />
          <operationBindings>
              <operationBinding operationType="custom" operationId="resetCustom" serverMethod="resetCustom" />
              <operationBinding operationType="custom" operationId="updateCustom" serverMethod="updateCustom" />
          </operationBindings>
      BuiltInDS.java:
      Code:
      package com.smartgwt.sample.client;
      
      import com.google.gwt.core.client.EntryPoint;
      import com.smartgwt.client.Version;
      import com.smartgwt.client.core.KeyIdentifier;
      import com.smartgwt.client.data.AdvancedCriteria;
      import com.smartgwt.client.data.DataSource;
      import com.smartgwt.client.data.SortSpecifier;
      import com.smartgwt.client.rpc.RPCManager;
      import com.smartgwt.client.types.OperatorId;
      import com.smartgwt.client.types.SortDirection;
      import com.smartgwt.client.util.Page;
      import com.smartgwt.client.util.PageKeyHandler;
      import com.smartgwt.client.util.SC;
      import com.smartgwt.client.widgets.IButton;
      import com.smartgwt.client.widgets.Window;
      import com.smartgwt.client.widgets.events.ClickEvent;
      import com.smartgwt.client.widgets.events.ClickHandler;
      import com.smartgwt.client.widgets.grid.ListGrid;
      import com.smartgwt.client.widgets.grid.ListGridField;
      import com.smartgwt.client.widgets.grid.ListGridRecord;
      import com.smartgwt.client.widgets.layout.HLayout;
      import com.smartgwt.client.widgets.layout.VLayout;
      
      public class BuiltInDS implements EntryPoint {
          private VLayout mainLayout;
          private IButton recreateBtn;
      
          public void onModuleLoad() {
              KeyIdentifier debugKey = new KeyIdentifier();
              debugKey.setCtrlKey(true);
              debugKey.setKeyName("D");
      
              Page.registerKey(debugKey, new PageKeyHandler() {
                  public void execute(String keyName) {
                      SC.showConsole();
                  }
              });
      
              mainLayout = new VLayout(20);
              mainLayout.setWidth100();
              mainLayout.setHeight100();
      
              recreateBtn = new IButton("Recreate");
              recreateBtn.addClickHandler(new ClickHandler() {
                  @Override
                  public void onClick(ClickEvent event) {
                      recreate();
                  }
              });
              mainLayout.addMember(recreateBtn);
              recreate();
              mainLayout.draw();
          }
      
          private void recreate() {
              Window w = new Window();
              w.setWidth("95%");
              w.setHeight("95%");
              w.setMembersMargin(0);
              w.setModalMaskOpacity(70);
              w.setTitle(" (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
              w.setTitle("Problem with failed queues and relatedUpdate" + w.getTitle());
              w.setShowMinimizeButton(false);
              w.setIsModal(true);
              w.setShowModalMask(true);
              w.centerInPage();
              final DataSource employeesDS = DataSource.get("employees");
              final ListGrid lg = new ListGrid(employeesDS);
              lg.setAutoFetchData(true);
              lg.setWidth(650);
              lg.setHeight100();
              lg.setSort(new SortSpecifier("EmployeeId", SortDirection.ASCENDING));
              lg.setInitialCriteria(new AdvancedCriteria("EmployeeId", OperatorId.LESS_OR_EQUAL, 190));
              ListGridField employeeId = new ListGridField("EmployeeId");
              ListGridField name = new ListGridField("Name");
              ListGridField salary = new ListGridField("Salary");
              lg.setFields(employeeId, name, salary);
      
              final IButton reloadBtn = new IButton("Reload data");
              reloadBtn.setWidth(200);
              reloadBtn.addClickHandler(new ClickHandler() {
                  @Override
                  public void onClick(ClickEvent event) {
                      lg.invalidateCache();
                  }
              });
              final IButton resetBtn = new IButton("Reset all data to 0");
              resetBtn.setWidth(200);
              resetBtn.addClickHandler(new ClickHandler() {
                  @Override
                  public void onClick(ClickEvent event) {
                      employeesDS.performCustomOperation("resetCustom");
                  }
              });
              final IButton changeBtn = new IButton("Change selected to 1000");
              changeBtn.setWidth(200);
              changeBtn.addClickHandler(new ClickHandler() {
                  @Override
                  public void onClick(ClickEvent event) {
                      RPCManager.startQueue();
                      for (ListGridRecord lgr : lg.getSelectedRecords()) {
                          employeesDS.performCustomOperation("updateCustom", lgr);
                      }
      
                      if (!RPCManager.hasCurrentTransactionQueued()) {
                          RPCManager.cancelQueue();
                          RPCManager.startQueue(false);
                      } else {
                          RPCManager.sendQueue();
                      }
                  }
              });
              HLayout buttonsLayout = new HLayout(10) {
                  {
                      addMembers(reloadBtn, resetBtn, changeBtn);
                  }
              };
              VLayout vLayout = new VLayout(10) {
                  {
                      addMembers(lg, buttonsLayout);
                  }
              };
              w.addItem(vLayout);
              w.show();
          }
      }
      Employees.java:
      Code:
      package com.smartgwt.sample.server.listener;
      
      import javax.servlet.http.HttpServletRequest;
      
      import com.isomorphic.criteria.AdvancedCriteria;
      import com.isomorphic.criteria.DefaultOperators;
      import com.isomorphic.criteria.criterion.SimpleCriterion;
      import com.isomorphic.datasource.DSRequest;
      import com.isomorphic.datasource.DSResponse;
      import com.isomorphic.datasource.DataSource;
      
      public class Employees {
          public DSResponse resetCustom(DSRequest request, HttpServletRequest servletRequest) throws Exception {
              DSRequest resetSalaryReq = new DSRequest(request.getDataSourceName(), DataSource.OP_UPDATE, request.getRPCManager());
              resetSalaryReq.setAllowMultiUpdate(true);
              resetSalaryReq.setFieldValue("Salary", 0);
              resetSalaryReq.setAdvancedCriteria(new AdvancedCriteria(new SimpleCriterion("EmployeeId", DefaultOperators.LessOrEqual, 190)));
              resetSalaryReq.execute();
      
              DSRequest fetchEmployeesReq = new DSRequest(request.getDataSourceName(), DataSource.OP_FETCH, request.getRPCManager());
              fetchEmployeesReq.setAdvancedCriteria(new AdvancedCriteria(new SimpleCriterion("EmployeeId", DefaultOperators.LessOrEqual, 190)));
              DSResponse fetchEmployeesResp = fetchEmployeesReq.execute();
      
              fetchEmployeesResp.setAffectedRows(fetchEmployeesResp.getTotalRows());
              fetchEmployeesResp.setOperationType(DataSource.OP_UPDATE);
      
              DSResponse myResponse = new DSResponse().setSuccess();
              myResponse.addRelatedUpdate(fetchEmployeesResp);
              return myResponse;
          }
      
          public DSResponse updateCustom(DSRequest request, HttpServletRequest servletRequest) throws Exception {
              Long employeeId = (Long) request.getValues().get("EmployeeId");
      
              if (employeeId.equals(4L) || employeeId.equals(182L))
                  return new DSResponse().setFailure("Editing of Charles Madigen and Tamara Kane forbidden");
      
              DSRequest updateSalaryReq = new DSRequest(request.getDataSourceName(), DataSource.OP_UPDATE, request.getRPCManager());
              updateSalaryReq.setFieldValue("Salary", 1000);
              updateSalaryReq.setAdvancedCriteria(new AdvancedCriteria(new SimpleCriterion("EmployeeId", DefaultOperators.Equals, employeeId)));
              DSResponse updateSalaryResp = updateSalaryReq.execute();
      
              DSResponse myResponse = new DSResponse().setSuccess();
              myResponse.addRelatedUpdate(updateSalaryResp);
              return myResponse;
          }
      }

      Comment

      Working...
      X